home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / com32 / lib / libpng / pnggccrd.c < prev    next >
Encoding:
Text File  |  2005-01-08  |  229.6 KB  |  5,409 lines

  1. /* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file
  2.  *
  3.  * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler.
  4.  *
  5.  *     See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm
  6.  *     and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm
  7.  *     for Intel's performance analysis of the MMX vs. non-MMX code.
  8.  *
  9.  * libpng version 1.2.8 - December 3, 2004
  10.  * For conditions of distribution and use, see copyright notice in png.h
  11.  * Copyright (c) 1998-2004 Glenn Randers-Pehrson
  12.  * Copyright (c) 1998, Intel Corporation
  13.  *
  14.  * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998.
  15.  * Interface to libpng contributed by Gilles Vollant, 1999.
  16.  * GNU C port by Greg Roelofs, 1999-2001.
  17.  *
  18.  * Lines 2350-4300 converted in place with intel2gas 1.3.1:
  19.  *
  20.  *   intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c
  21.  *
  22.  * and then cleaned up by hand.  See http://hermes.terminal.at/intel2gas/ .
  23.  *
  24.  * NOTE:  A sufficiently recent version of GNU as (or as.exe under DOS/Windows)
  25.  *        is required to assemble the newer MMX instructions such as movq.
  26.  *        For djgpp, see
  27.  *
  28.  *           ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip
  29.  *
  30.  *        (or a later version in the same directory).  For Linux, check your
  31.  *        distribution's web site(s) or try these links:
  32.  *
  33.  *           http://rufus.w3.org/linux/RPM/binutils.html
  34.  *           http://www.debian.org/Packages/stable/devel/binutils.html
  35.  *           ftp://ftp.slackware.com/pub/linux/slackware/slackware/slakware/d1/
  36.  *             binutils.tgz
  37.  *
  38.  *        For other platforms, see the main GNU site:
  39.  *
  40.  *           ftp://ftp.gnu.org/pub/gnu/binutils/
  41.  *
  42.  *        Version 2.5.2l.15 is definitely too old...
  43.  */
  44.  
  45. /*
  46.  * TEMPORARY PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs)
  47.  * =====================================
  48.  *
  49.  * 19991006:
  50.  *  - fixed sign error in post-MMX cleanup code (16- & 32-bit cases)
  51.  *
  52.  * 19991007:
  53.  *  - additional optimizations (possible or definite):
  54.  *     x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested]
  55.  *     - write MMX code for 48-bit case (pixel_bytes == 6)
  56.  *     - figure out what's up with 24-bit case (pixel_bytes == 3):
  57.  *        why subtract 8 from width_mmx in the pass 4/5 case?
  58.  *        (only width_mmx case) (near line 1606)
  59.  *     x [DONE] replace pixel_bytes within each block with the true
  60.  *        constant value (or are compilers smart enough to do that?)
  61.  *     - rewrite all MMX interlacing code so it's aligned with
  62.  *        the *beginning* of the row buffer, not the end.  This
  63.  *        would not only allow one to eliminate half of the memory
  64.  *        writes for odd passes (that is, pass == odd), it may also
  65.  *        eliminate some unaligned-data-access exceptions (assuming
  66.  *        there's a penalty for not aligning 64-bit accesses on
  67.  *        64-bit boundaries).  The only catch is that the "leftover"
  68.  *        pixel(s) at the end of the row would have to be saved,
  69.  *        but there are enough unused MMX registers in every case,
  70.  *        so this is not a problem.  A further benefit is that the
  71.  *        post-MMX cleanup code (C code) in at least some of the
  72.  *        cases could be done within the assembler block.
  73.  *  x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing,
  74.  *     inconsistent, and don't match the MMX Programmer's Reference
  75.  *     Manual conventions anyway.  They should be changed to
  76.  *     "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that
  77.  *     was lowest in memory (e.g., corresponding to a left pixel)
  78.  *     and b7 is the byte that was highest (e.g., a right pixel).
  79.  *
  80.  * 19991016:
  81.  *  - Brennan's Guide notwithstanding, gcc under Linux does *not*
  82.  *     want globals prefixed by underscores when referencing them--
  83.  *     i.e., if the variable is const4, then refer to it as const4,
  84.  *     not _const4.  This seems to be a djgpp-specific requirement.
  85.  *     Also, such variables apparently *must* be declared outside
  86.  *     of functions; neither static nor automatic variables work if
  87.  *     defined within the scope of a single function, but both
  88.  *     static and truly global (multi-module) variables work fine.
  89.  *
  90.  * 19991023:
  91.  *  - fixed png_combine_row() non-MMX replication bug (odd passes only?)
  92.  *  - switched from string-concatenation-with-macros to cleaner method of
  93.  *     renaming global variables for djgpp--i.e., always use prefixes in
  94.  *     inlined assembler code (== strings) and conditionally rename the
  95.  *     variables, not the other way around.  Hence _const4, _mask8_0, etc.
  96.  *
  97.  * 19991024:
  98.  *  - fixed mmxsupport()/png_do_read_interlace() first-row bug
  99.  *     This one was severely weird:  even though mmxsupport() doesn't touch
  100.  *     ebx (where "row" pointer was stored), it nevertheless managed to zero
  101.  *     the register (even in static/non-fPIC code--see below), which in turn
  102.  *     caused png_do_read_interlace() to return prematurely on the first row of
  103.  *     interlaced images (i.e., without expanding the interlaced pixels).
  104.  *     Inspection of the generated assembly code didn't turn up any clues,
  105.  *     although it did point at a minor optimization (i.e., get rid of
  106.  *     mmx_supported_local variable and just use eax).  Possibly the CPUID
  107.  *     instruction is more destructive than it looks?  (Not yet checked.)
  108.  *  - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly
  109.  *     listings...  Apparently register spillage has to do with ebx, since
  110.  *     it's used to index the global offset table.  Commenting it out of the
  111.  *     input-reg lists in png_combine_row() eliminated compiler barfage, so
  112.  *     ifdef'd with __PIC__ macro:  if defined, use a global for unmask
  113.  *
  114.  * 19991107:
  115.  *  - verified CPUID clobberage:  12-char string constant ("GenuineIntel",
  116.  *     "AuthenticAMD", etc.) placed in ebx:ecx:edx.  Still need to polish.
  117.  *
  118.  * 19991120:
  119.  *  - made "diff" variable (now "_dif") global to simplify conversion of
  120.  *     filtering routines (running out of regs, sigh).  "diff" is still used
  121.  *     in interlacing routines, however.
  122.  *  - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX
  123.  *     macro determines which is used); original not yet tested.
  124.  *
  125.  * 20000213:
  126.  *  - when compiling with gcc, be sure to use  -fomit-frame-pointer
  127.  *
  128.  * 20000319:
  129.  *  - fixed a register-name typo in png_do_read_interlace(), default (MMX) case,
  130.  *     pass == 4 or 5, that caused visible corruption of interlaced images
  131.  *
  132.  * 20000623:
  133.  *  - Various problems were reported with gcc 2.95.2 in the Cygwin environment,
  134.  *     many of the form "forbidden register 0 (ax) was spilled for class AREG."
  135.  *     This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and
  136.  *     Chuck Wilson supplied a patch involving dummy output registers.  See
  137.  *     http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624
  138.  *     for the original (anonymous) SourceForge bug report.
  139.  *
  140.  * 20000706:
  141.  *  - Chuck Wilson passed along these remaining gcc 2.95.2 errors:
  142.  *       pnggccrd.c: In function `png_combine_row':
  143.  *       pnggccrd.c:525: more than 10 operands in `asm'
  144.  *       pnggccrd.c:669: more than 10 operands in `asm'
  145.  *       pnggccrd.c:828: more than 10 operands in `asm'
  146.  *       pnggccrd.c:994: more than 10 operands in `asm'
  147.  *       pnggccrd.c:1177: more than 10 operands in `asm'
  148.  *     They are all the same problem and can be worked around by using the
  149.  *     global _unmask variable unconditionally, not just in the -fPIC case.
  150.  *     Reportedly earlier versions of gcc also have the problem with more than
  151.  *     10 operands; they just don't report it.  Much strangeness ensues, etc.
  152.  *
  153.  * 20000729:
  154.  *  - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted
  155.  *     MMX routine); began converting png_read_filter_row_mmx_sub()
  156.  *  - to finish remaining sections:
  157.  *     - clean up indentation and comments
  158.  *     - preload local variables
  159.  *     - add output and input regs (order of former determines numerical
  160.  *        mapping of latter)
  161.  *     - avoid all usage of ebx (including bx, bh, bl) register [20000823]
  162.  *     - remove "$" from addressing of Shift and Mask variables [20000823]
  163.  *
  164.  * 20000731:
  165.  *  - global union vars causing segfaults in png_read_filter_row_mmx_sub()?
  166.  *
  167.  * 20000822:
  168.  *  - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with
  169.  *     shared-library (-fPIC) version!  Code works just fine as part of static
  170.  *     library.  Damn damn damn damn damn, should have tested that sooner.
  171.  *     ebx is getting clobbered again (explicitly this time); need to save it
  172.  *     on stack or rewrite asm code to avoid using it altogether.  Blargh!
  173.  *
  174.  * 20000823:
  175.  *  - first section was trickiest; all remaining sections have ebx -> edx now.
  176.  *     (-fPIC works again.)  Also added missing underscores to various Shift*
  177.  *     and *Mask* globals and got rid of leading "$" signs.
  178.  *
  179.  * 20000826:
  180.  *  - added visual separators to help navigate microscopic printed copies
  181.  *     (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working
  182.  *     on png_read_filter_row_mmx_avg()
  183.  *
  184.  * 20000828:
  185.  *  - finished png_read_filter_row_mmx_avg():  only Paeth left! (930 lines...)
  186.  *     What the hell, did png_read_filter_row_mmx_paeth(), too.  Comments not
  187.  *     cleaned up/shortened in either routine, but functionality is complete
  188.  *     and seems to be working fine.
  189.  *
  190.  * 20000829:
  191.  *  - ahhh, figured out last(?) bit of gcc/gas asm-fu:  if register is listed
  192.  *     as an input reg (with dummy output variables, etc.), then it *cannot*
  193.  *     also appear in the clobber list or gcc 2.95.2 will barf.  The solution
  194.  *     is simple enough...
  195.  *
  196.  * 20000914:
  197.  *  - bug in png_read_filter_row_mmx_avg():  16-bit grayscale not handled
  198.  *     correctly (but 48-bit RGB just fine)
  199.  *
  200.  * 20000916:
  201.  *  - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors:
  202.  *     - "_ShiftBpp.use = 24;"      should have been   "_ShiftBpp.use = 16;"
  203.  *     - "_ShiftRem.use = 40;"      should have been   "_ShiftRem.use = 48;"
  204.  *     - "psllq _ShiftRem, %%mm2"   should have been   "psrlq _ShiftRem, %%mm2"
  205.  *
  206.  * 20010101:
  207.  *  - added new png_init_mmx_flags() function (here only because it needs to
  208.  *     call mmxsupport(), which should probably become global png_mmxsupport());
  209.  *     modified other MMX routines to run conditionally (png_ptr->asm_flags)
  210.  *
  211.  * 20010103:
  212.  *  - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported,
  213.  *     and made it public; moved png_init_mmx_flags() to png.c as internal func
  214.  *
  215.  * 20010104:
  216.  *  - removed dependency on png_read_filter_row_c() (C code already duplicated
  217.  *     within MMX version of png_read_filter_row()) so no longer necessary to
  218.  *     compile it into pngrutil.o
  219.  *
  220.  * 20010310:
  221.  *  - fixed buffer-overrun bug in png_combine_row() C code (non-MMX)
  222.  *
  223.  * 20020304:
  224.  *  - eliminated incorrect use of width_mmx in pixel_bytes == 8 case
  225.  *
  226.  * 20040724:
  227.  *   - more tinkering with clobber list at lines 4529 and 5033, to get
  228.  *     it to compile on gcc-3.4.
  229.  *
  230.  * STILL TO DO:
  231.  *     - test png_do_read_interlace() 64-bit case (pixel_bytes == 8)
  232.  *     - write MMX code for 48-bit case (pixel_bytes == 6)
  233.  *     - figure out what's up with 24-bit case (pixel_bytes == 3):
  234.  *        why subtract 8 from width_mmx in the pass 4/5 case?
  235.  *        (only width_mmx case) (near line 1606)
  236.  *     - rewrite all MMX interlacing code so it's aligned with beginning
  237.  *        of the row buffer, not the end (see 19991007 for details)
  238.  *     x pick one version of mmxsupport() and get rid of the other
  239.  *     - add error messages to any remaining bogus default cases
  240.  *     - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed)
  241.  *     x add support for runtime enable/disable/query of various MMX routines
  242.  */
  243.  
  244. #define PNG_INTERNAL
  245. #include "png.h"
  246.  
  247. #if defined(PNG_USE_PNGGCCRD)
  248.  
  249. int PNGAPI png_mmx_support(void);
  250.  
  251. #ifdef PNG_USE_LOCAL_ARRAYS
  252. static const int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
  253. static const int FARDATA png_pass_inc[7]   = {8, 8, 4, 4, 2, 2, 1};
  254. static const int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1};
  255. #endif
  256.  
  257. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  258. /* djgpp, Win32, and Cygwin add their own underscores to global variables,
  259.  * so define them without: */
  260. #if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__)
  261. #  define _mmx_supported  mmx_supported
  262. #  define _const4         const4
  263. #  define _const6         const6
  264. #  define _mask8_0        mask8_0
  265. #  define _mask16_1       mask16_1
  266. #  define _mask16_0       mask16_0
  267. #  define _mask24_2       mask24_2
  268. #  define _mask24_1       mask24_1
  269. #  define _mask24_0       mask24_0
  270. #  define _mask32_3       mask32_3
  271. #  define _mask32_2       mask32_2
  272. #  define _mask32_1       mask32_1
  273. #  define _mask32_0       mask32_0
  274. #  define _mask48_5       mask48_5
  275. #  define _mask48_4       mask48_4
  276. #  define _mask48_3       mask48_3
  277. #  define _mask48_2       mask48_2
  278. #  define _mask48_1       mask48_1
  279. #  define _mask48_0       mask48_0
  280. #  define _LBCarryMask    LBCarryMask
  281. #  define _HBClearMask    HBClearMask
  282. #  define _ActiveMask     ActiveMask
  283. #  define _ActiveMask2    ActiveMask2
  284. #  define _ActiveMaskEnd  ActiveMaskEnd
  285. #  define _ShiftBpp       ShiftBpp
  286. #  define _ShiftRem       ShiftRem
  287. #ifdef PNG_THREAD_UNSAFE_OK
  288. #  define _unmask         unmask
  289. #  define _FullLength     FullLength
  290. #  define _MMXLength      MMXLength
  291. #  define _dif            dif
  292. #  define _patemp         patemp
  293. #  define _pbtemp         pbtemp
  294. #  define _pctemp         pctemp
  295. #endif
  296. #endif
  297.  
  298.  
  299. /* These constants are used in the inlined MMX assembly code.
  300.    Ignore gcc's "At top level: defined but not used" warnings. */
  301.  
  302. /* GRR 20000706:  originally _unmask was needed only when compiling with -fPIC,
  303.  *  since that case uses the %ebx register for indexing the Global Offset Table
  304.  *  and there were no other registers available.  But gcc 2.95 and later emit
  305.  *  "more than 10 operands in `asm'" errors when %ebx is used to preload unmask
  306.  *  in the non-PIC case, so we'll just use the global unconditionally now.
  307.  */
  308. #ifdef PNG_THREAD_UNSAFE_OK
  309. static int _unmask;
  310. #endif
  311.  
  312. static unsigned long long _mask8_0  = 0x0102040810204080LL;
  313.  
  314. static unsigned long long _mask16_1 = 0x0101020204040808LL;
  315. static unsigned long long _mask16_0 = 0x1010202040408080LL;
  316.  
  317. static unsigned long long _mask24_2 = 0x0101010202020404LL;
  318. static unsigned long long _mask24_1 = 0x0408080810101020LL;
  319. static unsigned long long _mask24_0 = 0x2020404040808080LL;
  320.  
  321. static unsigned long long _mask32_3 = 0x0101010102020202LL;
  322. static unsigned long long _mask32_2 = 0x0404040408080808LL;
  323. static unsigned long long _mask32_1 = 0x1010101020202020LL;
  324. static unsigned long long _mask32_0 = 0x4040404080808080LL;
  325.  
  326. static unsigned long long _mask48_5 = 0x0101010101010202LL;
  327. static unsigned long long _mask48_4 = 0x0202020204040404LL;
  328. static unsigned long long _mask48_3 = 0x0404080808080808LL;
  329. static unsigned long long _mask48_2 = 0x1010101010102020LL;
  330. static unsigned long long _mask48_1 = 0x2020202040404040LL;
  331. static unsigned long long _mask48_0 = 0x4040808080808080LL;
  332.  
  333. static unsigned long long _const4   = 0x0000000000FFFFFFLL;
  334. //static unsigned long long _const5 = 0x000000FFFFFF0000LL;     // NOT USED
  335. static unsigned long long _const6   = 0x00000000000000FFLL;
  336.  
  337. // These are used in the row-filter routines and should/would be local
  338. //  variables if not for gcc addressing limitations.
  339. // WARNING: Their presence probably defeats the thread safety of libpng.
  340.  
  341. #ifdef PNG_THREAD_UNSAFE_OK
  342. static png_uint_32  _FullLength;
  343. static png_uint_32  _MMXLength;
  344. static int          _dif;
  345. static int          _patemp; // temp variables for Paeth routine
  346. static int          _pbtemp;
  347. static int          _pctemp;
  348. #endif
  349.  
  350. void /* PRIVATE */
  351. png_squelch_warnings(void)
  352. {
  353. #ifdef PNG_THREAD_UNSAFE_OK
  354.    _dif = _dif;
  355.    _patemp = _patemp;
  356.    _pbtemp = _pbtemp;
  357.    _pctemp = _pctemp;
  358.    _MMXLength = _MMXLength;
  359. #endif
  360.    _const4  = _const4;
  361.    _const6  = _const6;
  362.    _mask8_0  = _mask8_0;
  363.    _mask16_1 = _mask16_1;
  364.    _mask16_0 = _mask16_0;
  365.    _mask24_2 = _mask24_2;
  366.    _mask24_1 = _mask24_1;
  367.    _mask24_0 = _mask24_0;
  368.    _mask32_3 = _mask32_3;
  369.    _mask32_2 = _mask32_2;
  370.    _mask32_1 = _mask32_1;
  371.    _mask32_0 = _mask32_0;
  372.    _mask48_5 = _mask48_5;
  373.    _mask48_4 = _mask48_4;
  374.    _mask48_3 = _mask48_3;
  375.    _mask48_2 = _mask48_2;
  376.    _mask48_1 = _mask48_1;
  377.    _mask48_0 = _mask48_0;
  378. }
  379. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  380.  
  381.  
  382. static int _mmx_supported = 2;
  383.  
  384. /*===========================================================================*/
  385. /*                                                                           */
  386. /*                       P N G _ C O M B I N E _ R O W                       */
  387. /*                                                                           */
  388. /*===========================================================================*/
  389.  
  390. #if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW)
  391.  
  392. #define BPP2  2
  393. #define BPP3  3 /* bytes per pixel (a.k.a. pixel_bytes) */
  394. #define BPP4  4
  395. #define BPP6  6 /* (defined only to help avoid cut-and-paste errors) */
  396. #define BPP8  8
  397.  
  398. /* Combines the row recently read in with the previous row.
  399.    This routine takes care of alpha and transparency if requested.
  400.    This routine also handles the two methods of progressive display
  401.    of interlaced images, depending on the mask value.
  402.    The mask value describes which pixels are to be combined with
  403.    the row.  The pattern always repeats every 8 pixels, so just 8
  404.    bits are needed.  A one indicates the pixel is to be combined; a
  405.    zero indicates the pixel is to be skipped.  This is in addition
  406.    to any alpha or transparency value associated with the pixel.
  407.    If you want all pixels to be combined, pass 0xff (255) in mask. */
  408.  
  409. /* Use this routine for the x86 platform - it uses a faster MMX routine
  410.    if the machine supports MMX. */
  411.  
  412. void /* PRIVATE */
  413. png_combine_row(png_structp png_ptr, png_bytep row, int mask)
  414. {
  415.    png_debug(1, "in png_combine_row (pnggccrd.c)\n");
  416.  
  417. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  418.    if (_mmx_supported == 2) {
  419. #if !defined(PNG_1_0_X)
  420.        /* this should have happened in png_init_mmx_flags() already */
  421.        png_warning(png_ptr, "asm_flags may not have been initialized");
  422. #endif
  423.        png_mmx_support();
  424.    }
  425. #endif
  426.  
  427.    if (mask == 0xff)
  428.    {
  429.       png_debug(2,"mask == 0xff:  doing single png_memcpy()\n");
  430.       png_memcpy(row, png_ptr->row_buf + 1,
  431.        (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,png_ptr->width));
  432.    }
  433.    else   /* (png_combine_row() is never called with mask == 0) */
  434.    {
  435.       switch (png_ptr->row_info.pixel_depth)
  436.       {
  437.          case 1:        /* png_ptr->row_info.pixel_depth */
  438.          {
  439.             png_bytep sp;
  440.             png_bytep dp;
  441.             int s_inc, s_start, s_end;
  442.             int m;
  443.             int shift;
  444.             png_uint_32 i;
  445.  
  446.             sp = png_ptr->row_buf + 1;
  447.             dp = row;
  448.             m = 0x80;
  449. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  450.             if (png_ptr->transformations & PNG_PACKSWAP)
  451.             {
  452.                 s_start = 0;
  453.                 s_end = 7;
  454.                 s_inc = 1;
  455.             }
  456.             else
  457. #endif
  458.             {
  459.                 s_start = 7;
  460.                 s_end = 0;
  461.                 s_inc = -1;
  462.             }
  463.  
  464.             shift = s_start;
  465.  
  466.             for (i = 0; i < png_ptr->width; i++)
  467.             {
  468.                if (m & mask)
  469.                {
  470.                   int value;
  471.  
  472.                   value = (*sp >> shift) & 0x1;
  473.                   *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
  474.                   *dp |= (png_byte)(value << shift);
  475.                }
  476.  
  477.                if (shift == s_end)
  478.                {
  479.                   shift = s_start;
  480.                   sp++;
  481.                   dp++;
  482.                }
  483.                else
  484.                   shift += s_inc;
  485.  
  486.                if (m == 1)
  487.                   m = 0x80;
  488.                else
  489.                   m >>= 1;
  490.             }
  491.             break;
  492.          }
  493.  
  494.          case 2:        /* png_ptr->row_info.pixel_depth */
  495.          {
  496.             png_bytep sp;
  497.             png_bytep dp;
  498.             int s_start, s_end, s_inc;
  499.             int m;
  500.             int shift;
  501.             png_uint_32 i;
  502.             int value;
  503.  
  504.             sp = png_ptr->row_buf + 1;
  505.             dp = row;
  506.             m = 0x80;
  507. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  508.             if (png_ptr->transformations & PNG_PACKSWAP)
  509.             {
  510.                s_start = 0;
  511.                s_end = 6;
  512.                s_inc = 2;
  513.             }
  514.             else
  515. #endif
  516.             {
  517.                s_start = 6;
  518.                s_end = 0;
  519.                s_inc = -2;
  520.             }
  521.  
  522.             shift = s_start;
  523.  
  524.             for (i = 0; i < png_ptr->width; i++)
  525.             {
  526.                if (m & mask)
  527.                {
  528.                   value = (*sp >> shift) & 0x3;
  529.                   *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
  530.                   *dp |= (png_byte)(value << shift);
  531.                }
  532.  
  533.                if (shift == s_end)
  534.                {
  535.                   shift = s_start;
  536.                   sp++;
  537.                   dp++;
  538.                }
  539.                else
  540.                   shift += s_inc;
  541.                if (m == 1)
  542.                   m = 0x80;
  543.                else
  544.                   m >>= 1;
  545.             }
  546.             break;
  547.          }
  548.  
  549.          case 4:        /* png_ptr->row_info.pixel_depth */
  550.          {
  551.             png_bytep sp;
  552.             png_bytep dp;
  553.             int s_start, s_end, s_inc;
  554.             int m;
  555.             int shift;
  556.             png_uint_32 i;
  557.             int value;
  558.  
  559.             sp = png_ptr->row_buf + 1;
  560.             dp = row;
  561.             m = 0x80;
  562. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  563.             if (png_ptr->transformations & PNG_PACKSWAP)
  564.             {
  565.                s_start = 0;
  566.                s_end = 4;
  567.                s_inc = 4;
  568.             }
  569.             else
  570. #endif
  571.             {
  572.                s_start = 4;
  573.                s_end = 0;
  574.                s_inc = -4;
  575.             }
  576.             shift = s_start;
  577.  
  578.             for (i = 0; i < png_ptr->width; i++)
  579.             {
  580.                if (m & mask)
  581.                {
  582.                   value = (*sp >> shift) & 0xf;
  583.                   *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
  584.                   *dp |= (png_byte)(value << shift);
  585.                }
  586.  
  587.                if (shift == s_end)
  588.                {
  589.                   shift = s_start;
  590.                   sp++;
  591.                   dp++;
  592.                }
  593.                else
  594.                   shift += s_inc;
  595.                if (m == 1)
  596.                   m = 0x80;
  597.                else
  598.                   m >>= 1;
  599.             }
  600.             break;
  601.          }
  602.  
  603.          case 8:        /* png_ptr->row_info.pixel_depth */
  604.          {
  605.             png_bytep srcptr;
  606.             png_bytep dstptr;
  607.  
  608. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  609. #if !defined(PNG_1_0_X)
  610.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
  611.                 /* && _mmx_supported */ )
  612. #else
  613.             if (_mmx_supported)
  614. #endif
  615.             {
  616.                png_uint_32 len;
  617.                int diff;
  618.                int dummy_value_a;   // fix 'forbidden register spilled' error
  619.                int dummy_value_d;
  620.                int dummy_value_c;
  621.                int dummy_value_S;
  622.                int dummy_value_D;
  623.                _unmask = ~mask;            // global variable for -fPIC version
  624.                srcptr = png_ptr->row_buf + 1;
  625.                dstptr = row;
  626.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  627.                diff = (int) (png_ptr->width & 7);  // amount lost
  628.  
  629.                __asm__ __volatile__ (
  630.                   "movd      _unmask, %%mm7  \n\t" // load bit pattern
  631.                   "psubb     %%mm6, %%mm6    \n\t" // zero mm6
  632.                   "punpcklbw %%mm7, %%mm7    \n\t"
  633.                   "punpcklwd %%mm7, %%mm7    \n\t"
  634.                   "punpckldq %%mm7, %%mm7    \n\t" // fill reg with 8 masks
  635.  
  636.                   "movq      _mask8_0, %%mm0 \n\t"
  637.                   "pand      %%mm7, %%mm0    \n\t" // nonzero if keep byte
  638.                   "pcmpeqb   %%mm6, %%mm0    \n\t" // zeros->1s, v versa
  639.  
  640. // preload        "movl      len, %%ecx      \n\t" // load length of line
  641. // preload        "movl      srcptr, %%esi   \n\t" // load source
  642. // preload        "movl      dstptr, %%edi   \n\t" // load dest
  643.  
  644.                   "cmpl      $0, %%ecx       \n\t" // len == 0 ?
  645.                   "je        mainloop8end    \n\t"
  646.  
  647.                 "mainloop8:                  \n\t"
  648.                   "movq      (%%esi), %%mm4  \n\t" // *srcptr
  649.                   "pand      %%mm0, %%mm4    \n\t"
  650.                   "movq      %%mm0, %%mm6    \n\t"
  651.                   "pandn     (%%edi), %%mm6  \n\t" // *dstptr
  652.                   "por       %%mm6, %%mm4    \n\t"
  653.                   "movq      %%mm4, (%%edi)  \n\t"
  654.                   "addl      $8, %%esi       \n\t" // inc by 8 bytes processed
  655.                   "addl      $8, %%edi       \n\t"
  656.                   "subl      $8, %%ecx       \n\t" // dec by 8 pixels processed
  657.                   "ja        mainloop8       \n\t"
  658.  
  659.                 "mainloop8end:               \n\t"
  660. // preload        "movl      diff, %%ecx     \n\t" // (diff is in eax)
  661.                   "movl      %%eax, %%ecx    \n\t"
  662.                   "cmpl      $0, %%ecx       \n\t"
  663.                   "jz        end8            \n\t"
  664. // preload        "movl      mask, %%edx     \n\t"
  665.                   "sall      $24, %%edx      \n\t" // make low byte, high byte
  666.  
  667.                 "secondloop8:                \n\t"
  668.                   "sall      %%edx           \n\t" // move high bit to CF
  669.                   "jnc       skip8           \n\t" // if CF = 0
  670.                   "movb      (%%esi), %%al   \n\t"
  671.                   "movb      %%al, (%%edi)   \n\t"
  672.  
  673.                 "skip8:                      \n\t"
  674.                   "incl      %%esi           \n\t"
  675.                   "incl      %%edi           \n\t"
  676.                   "decl      %%ecx           \n\t"
  677.                   "jnz       secondloop8     \n\t"
  678.  
  679.                 "end8:                       \n\t"
  680.                   "EMMS                      \n\t"  // DONE
  681.  
  682.                   : "=a" (dummy_value_a),           // output regs (dummy)
  683.                     "=d" (dummy_value_d),
  684.                     "=c" (dummy_value_c),
  685.                     "=S" (dummy_value_S),
  686.                     "=D" (dummy_value_D)
  687.  
  688.                   : "3" (srcptr),      // esi       // input regs
  689.                     "4" (dstptr),      // edi
  690.                     "0" (diff),        // eax
  691. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  692.                     "2" (len),         // ecx
  693.                     "1" (mask)         // edx
  694.  
  695. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  696.                   : "%mm0", "%mm4", "%mm6", "%mm7"  // clobber list
  697. #endif
  698.                );
  699.             }
  700.             else /* mmx _not supported - Use modified C routine */
  701. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  702.             {
  703.                register png_uint_32 i;
  704.                png_uint_32 initial_val = png_pass_start[png_ptr->pass];
  705.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  706.                register int stride = png_pass_inc[png_ptr->pass];
  707.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  708.                register int rep_bytes = png_pass_width[png_ptr->pass];
  709.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  710.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  711.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  712.                register png_uint_32 final_val = len;  /* GRR bugfix */
  713.  
  714.                srcptr = png_ptr->row_buf + 1 + initial_val;
  715.                dstptr = row + initial_val;
  716.  
  717.                for (i = initial_val; i < final_val; i += stride)
  718.                {
  719.                   png_memcpy(dstptr, srcptr, rep_bytes);
  720.                   srcptr += stride;
  721.                   dstptr += stride;
  722.                }
  723.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  724.                {
  725.                   final_val+=diff /* *BPP1 */ ;
  726.                   for (; i < final_val; i += stride)
  727.                   {
  728.                      if (rep_bytes > (int)(final_val-i))
  729.                         rep_bytes = (int)(final_val-i);
  730.                      png_memcpy(dstptr, srcptr, rep_bytes);
  731.                      srcptr += stride;
  732.                      dstptr += stride;
  733.                   }
  734.                }
  735.  
  736.             } /* end of else (_mmx_supported) */
  737.  
  738.             break;
  739.          }       /* end 8 bpp */
  740.  
  741.          case 16:       /* png_ptr->row_info.pixel_depth */
  742.          {
  743.             png_bytep srcptr;
  744.             png_bytep dstptr;
  745.  
  746. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  747. #if !defined(PNG_1_0_X)
  748.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
  749.                 /* && _mmx_supported */ )
  750. #else
  751.             if (_mmx_supported)
  752. #endif
  753.             {
  754.                png_uint_32 len;
  755.                int diff;
  756.                int dummy_value_a;   // fix 'forbidden register spilled' error
  757.                int dummy_value_d;
  758.                int dummy_value_c;
  759.                int dummy_value_S;
  760.                int dummy_value_D;
  761.                _unmask = ~mask;            // global variable for -fPIC version
  762.                srcptr = png_ptr->row_buf + 1;
  763.                dstptr = row;
  764.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  765.                diff = (int) (png_ptr->width & 7); // amount lost //
  766.  
  767.                __asm__ __volatile__ (
  768.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  769.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  770.                   "punpcklbw %%mm7, %%mm7     \n\t"
  771.                   "punpcklwd %%mm7, %%mm7     \n\t"
  772.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  773.  
  774.                   "movq      _mask16_0, %%mm0 \n\t"
  775.                   "movq      _mask16_1, %%mm1 \n\t"
  776.  
  777.                   "pand      %%mm7, %%mm0     \n\t"
  778.                   "pand      %%mm7, %%mm1     \n\t"
  779.  
  780.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  781.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  782.  
  783. // preload        "movl      len, %%ecx       \n\t" // load length of line
  784. // preload        "movl      srcptr, %%esi    \n\t" // load source
  785. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  786.  
  787.                   "cmpl      $0, %%ecx        \n\t"
  788.                   "jz        mainloop16end    \n\t"
  789.  
  790.                 "mainloop16:                  \n\t"
  791.                   "movq      (%%esi), %%mm4   \n\t"
  792.                   "pand      %%mm0, %%mm4     \n\t"
  793.                   "movq      %%mm0, %%mm6     \n\t"
  794.                   "movq      (%%edi), %%mm7   \n\t"
  795.                   "pandn     %%mm7, %%mm6     \n\t"
  796.                   "por       %%mm6, %%mm4     \n\t"
  797.                   "movq      %%mm4, (%%edi)   \n\t"
  798.  
  799.                   "movq      8(%%esi), %%mm5  \n\t"
  800.                   "pand      %%mm1, %%mm5     \n\t"
  801.                   "movq      %%mm1, %%mm7     \n\t"
  802.                   "movq      8(%%edi), %%mm6  \n\t"
  803.                   "pandn     %%mm6, %%mm7     \n\t"
  804.                   "por       %%mm7, %%mm5     \n\t"
  805.                   "movq      %%mm5, 8(%%edi)  \n\t"
  806.  
  807.                   "addl      $16, %%esi       \n\t" // inc by 16 bytes processed
  808.                   "addl      $16, %%edi       \n\t"
  809.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  810.                   "ja        mainloop16       \n\t"
  811.  
  812.                 "mainloop16end:               \n\t"
  813. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  814.                   "movl      %%eax, %%ecx     \n\t"
  815.                   "cmpl      $0, %%ecx        \n\t"
  816.                   "jz        end16            \n\t"
  817. // preload        "movl      mask, %%edx      \n\t"
  818.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  819.  
  820.                 "secondloop16:                \n\t"
  821.                   "sall      %%edx            \n\t" // move high bit to CF
  822.                   "jnc       skip16           \n\t" // if CF = 0
  823.                   "movw      (%%esi), %%ax    \n\t"
  824.                   "movw      %%ax, (%%edi)    \n\t"
  825.  
  826.                 "skip16:                      \n\t"
  827.                   "addl      $2, %%esi        \n\t"
  828.                   "addl      $2, %%edi        \n\t"
  829.                   "decl      %%ecx            \n\t"
  830.                   "jnz       secondloop16     \n\t"
  831.  
  832.                 "end16:                       \n\t"
  833.                   "EMMS                       \n\t" // DONE
  834.  
  835.                   : "=a" (dummy_value_a),           // output regs (dummy)
  836.                     "=c" (dummy_value_c),
  837.                     "=d" (dummy_value_d),
  838.                     "=S" (dummy_value_S),
  839.                     "=D" (dummy_value_D)
  840.  
  841.                   : "0" (diff),        // eax       // input regs
  842. // was (unmask)     " "    RESERVED    // ebx       // Global Offset Table idx
  843.                     "1" (len),         // ecx
  844.                     "2" (mask),        // edx
  845.                     "3" (srcptr),      // esi
  846.                     "4" (dstptr)       // edi
  847.  
  848. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  849.                   : "%mm0", "%mm1", "%mm4"          // clobber list
  850.                   , "%mm5", "%mm6", "%mm7"
  851. #endif
  852.                );
  853.             }
  854.             else /* mmx _not supported - Use modified C routine */
  855. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  856.             {
  857.                register png_uint_32 i;
  858.                png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass];
  859.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  860.                register int stride = BPP2 * png_pass_inc[png_ptr->pass];
  861.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  862.                register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass];
  863.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  864.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  865.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  866.                register png_uint_32 final_val = BPP2 * len;   /* GRR bugfix */
  867.  
  868.                srcptr = png_ptr->row_buf + 1 + initial_val;
  869.                dstptr = row + initial_val;
  870.  
  871.                for (i = initial_val; i < final_val; i += stride)
  872.                {
  873.                   png_memcpy(dstptr, srcptr, rep_bytes);
  874.                   srcptr += stride;
  875.                   dstptr += stride;
  876.                }
  877.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  878.                {
  879.                   final_val+=diff*BPP2;
  880.                   for (; i < final_val; i += stride)
  881.                   {
  882.                      if (rep_bytes > (int)(final_val-i))
  883.                         rep_bytes = (int)(final_val-i);
  884.                      png_memcpy(dstptr, srcptr, rep_bytes);
  885.                      srcptr += stride;
  886.                      dstptr += stride;
  887.                   }
  888.                }
  889.             } /* end of else (_mmx_supported) */
  890.  
  891.             break;
  892.          }       /* end 16 bpp */
  893.  
  894.          case 24:       /* png_ptr->row_info.pixel_depth */
  895.          {
  896.             png_bytep srcptr;
  897.             png_bytep dstptr;
  898.  
  899. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  900. #if !defined(PNG_1_0_X)
  901.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
  902.                 /* && _mmx_supported */ )
  903. #else
  904.             if (_mmx_supported)
  905. #endif
  906.             {
  907.                png_uint_32 len;
  908.                int diff;
  909.                int dummy_value_a;   // fix 'forbidden register spilled' error
  910.                int dummy_value_d;
  911.                int dummy_value_c;
  912.                int dummy_value_S;
  913.                int dummy_value_D;
  914.                _unmask = ~mask;            // global variable for -fPIC version
  915.                srcptr = png_ptr->row_buf + 1;
  916.                dstptr = row;
  917.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  918.                diff = (int) (png_ptr->width & 7); // amount lost //
  919.  
  920.                __asm__ __volatile__ (
  921.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  922.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  923.                   "punpcklbw %%mm7, %%mm7     \n\t"
  924.                   "punpcklwd %%mm7, %%mm7     \n\t"
  925.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  926.  
  927.                   "movq      _mask24_0, %%mm0 \n\t"
  928.                   "movq      _mask24_1, %%mm1 \n\t"
  929.                   "movq      _mask24_2, %%mm2 \n\t"
  930.  
  931.                   "pand      %%mm7, %%mm0     \n\t"
  932.                   "pand      %%mm7, %%mm1     \n\t"
  933.                   "pand      %%mm7, %%mm2     \n\t"
  934.  
  935.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  936.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  937.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  938.  
  939. // preload        "movl      len, %%ecx       \n\t" // load length of line
  940. // preload        "movl      srcptr, %%esi    \n\t" // load source
  941. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  942.  
  943.                   "cmpl      $0, %%ecx        \n\t"
  944.                   "jz        mainloop24end    \n\t"
  945.  
  946.                 "mainloop24:                  \n\t"
  947.                   "movq      (%%esi), %%mm4   \n\t"
  948.                   "pand      %%mm0, %%mm4     \n\t"
  949.                   "movq      %%mm0, %%mm6     \n\t"
  950.                   "movq      (%%edi), %%mm7   \n\t"
  951.                   "pandn     %%mm7, %%mm6     \n\t"
  952.                   "por       %%mm6, %%mm4     \n\t"
  953.                   "movq      %%mm4, (%%edi)   \n\t"
  954.  
  955.                   "movq      8(%%esi), %%mm5  \n\t"
  956.                   "pand      %%mm1, %%mm5     \n\t"
  957.                   "movq      %%mm1, %%mm7     \n\t"
  958.                   "movq      8(%%edi), %%mm6  \n\t"
  959.                   "pandn     %%mm6, %%mm7     \n\t"
  960.                   "por       %%mm7, %%mm5     \n\t"
  961.                   "movq      %%mm5, 8(%%edi)  \n\t"
  962.  
  963.                   "movq      16(%%esi), %%mm6 \n\t"
  964.                   "pand      %%mm2, %%mm6     \n\t"
  965.                   "movq      %%mm2, %%mm4     \n\t"
  966.                   "movq      16(%%edi), %%mm7 \n\t"
  967.                   "pandn     %%mm7, %%mm4     \n\t"
  968.                   "por       %%mm4, %%mm6     \n\t"
  969.                   "movq      %%mm6, 16(%%edi) \n\t"
  970.  
  971.                   "addl      $24, %%esi       \n\t" // inc by 24 bytes processed
  972.                   "addl      $24, %%edi       \n\t"
  973.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  974.  
  975.                   "ja        mainloop24       \n\t"
  976.  
  977.                 "mainloop24end:               \n\t"
  978. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  979.                   "movl      %%eax, %%ecx     \n\t"
  980.                   "cmpl      $0, %%ecx        \n\t"
  981.                   "jz        end24            \n\t"
  982. // preload        "movl      mask, %%edx      \n\t"
  983.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  984.  
  985.                 "secondloop24:                \n\t"
  986.                   "sall      %%edx            \n\t" // move high bit to CF
  987.                   "jnc       skip24           \n\t" // if CF = 0
  988.                   "movw      (%%esi), %%ax    \n\t"
  989.                   "movw      %%ax, (%%edi)    \n\t"
  990.                   "xorl      %%eax, %%eax     \n\t"
  991.                   "movb      2(%%esi), %%al   \n\t"
  992.                   "movb      %%al, 2(%%edi)   \n\t"
  993.  
  994.                 "skip24:                      \n\t"
  995.                   "addl      $3, %%esi        \n\t"
  996.                   "addl      $3, %%edi        \n\t"
  997.                   "decl      %%ecx            \n\t"
  998.                   "jnz       secondloop24     \n\t"
  999.  
  1000.                 "end24:                       \n\t"
  1001.                   "EMMS                       \n\t" // DONE
  1002.  
  1003.                   : "=a" (dummy_value_a),           // output regs (dummy)
  1004.                     "=d" (dummy_value_d),
  1005.                     "=c" (dummy_value_c),
  1006.                     "=S" (dummy_value_S),
  1007.                     "=D" (dummy_value_D)
  1008.  
  1009.                   : "3" (srcptr),      // esi       // input regs
  1010.                     "4" (dstptr),      // edi
  1011.                     "0" (diff),        // eax
  1012. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  1013.                     "2" (len),         // ecx
  1014.                     "1" (mask)         // edx
  1015.  
  1016. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1017.                   : "%mm0", "%mm1", "%mm2"          // clobber list
  1018.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  1019. #endif
  1020.                );
  1021.             }
  1022.             else /* mmx _not supported - Use modified C routine */
  1023. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  1024.             {
  1025.                register png_uint_32 i;
  1026.                png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass];
  1027.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1028.                register int stride = BPP3 * png_pass_inc[png_ptr->pass];
  1029.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1030.                register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass];
  1031.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1032.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1033.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  1034.                register png_uint_32 final_val = BPP3 * len;   /* GRR bugfix */
  1035.  
  1036.                srcptr = png_ptr->row_buf + 1 + initial_val;
  1037.                dstptr = row + initial_val;
  1038.  
  1039.                for (i = initial_val; i < final_val; i += stride)
  1040.                {
  1041.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1042.                   srcptr += stride;
  1043.                   dstptr += stride;
  1044.                }
  1045.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  1046.                {
  1047.                   final_val+=diff*BPP3;
  1048.                   for (; i < final_val; i += stride)
  1049.                   {
  1050.                      if (rep_bytes > (int)(final_val-i))
  1051.                         rep_bytes = (int)(final_val-i);
  1052.                      png_memcpy(dstptr, srcptr, rep_bytes);
  1053.                      srcptr += stride;
  1054.                      dstptr += stride;
  1055.                   }
  1056.                }
  1057.             } /* end of else (_mmx_supported) */
  1058.  
  1059.             break;
  1060.          }       /* end 24 bpp */
  1061.  
  1062.          case 32:       /* png_ptr->row_info.pixel_depth */
  1063.          {
  1064.             png_bytep srcptr;
  1065.             png_bytep dstptr;
  1066.  
  1067. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  1068. #if !defined(PNG_1_0_X)
  1069.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
  1070.                 /* && _mmx_supported */ )
  1071. #else
  1072.             if (_mmx_supported)
  1073. #endif
  1074.             {
  1075.                png_uint_32 len;
  1076.                int diff;
  1077.                int dummy_value_a;   // fix 'forbidden register spilled' error
  1078.                int dummy_value_d;
  1079.                int dummy_value_c;
  1080.                int dummy_value_S;
  1081.                int dummy_value_D;
  1082.                _unmask = ~mask;            // global variable for -fPIC version
  1083.                srcptr = png_ptr->row_buf + 1;
  1084.                dstptr = row;
  1085.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  1086.                diff = (int) (png_ptr->width & 7); // amount lost //
  1087.  
  1088.                __asm__ __volatile__ (
  1089.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  1090.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  1091.                   "punpcklbw %%mm7, %%mm7     \n\t"
  1092.                   "punpcklwd %%mm7, %%mm7     \n\t"
  1093.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  1094.  
  1095.                   "movq      _mask32_0, %%mm0 \n\t"
  1096.                   "movq      _mask32_1, %%mm1 \n\t"
  1097.                   "movq      _mask32_2, %%mm2 \n\t"
  1098.                   "movq      _mask32_3, %%mm3 \n\t"
  1099.  
  1100.                   "pand      %%mm7, %%mm0     \n\t"
  1101.                   "pand      %%mm7, %%mm1     \n\t"
  1102.                   "pand      %%mm7, %%mm2     \n\t"
  1103.                   "pand      %%mm7, %%mm3     \n\t"
  1104.  
  1105.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  1106.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  1107.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  1108.                   "pcmpeqb   %%mm6, %%mm3     \n\t"
  1109.  
  1110. // preload        "movl      len, %%ecx       \n\t" // load length of line
  1111. // preload        "movl      srcptr, %%esi    \n\t" // load source
  1112. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  1113.  
  1114.                   "cmpl      $0, %%ecx        \n\t" // lcr
  1115.                   "jz        mainloop32end    \n\t"
  1116.  
  1117.                 "mainloop32:                  \n\t"
  1118.                   "movq      (%%esi), %%mm4   \n\t"
  1119.                   "pand      %%mm0, %%mm4     \n\t"
  1120.                   "movq      %%mm0, %%mm6     \n\t"
  1121.                   "movq      (%%edi), %%mm7   \n\t"
  1122.                   "pandn     %%mm7, %%mm6     \n\t"
  1123.                   "por       %%mm6, %%mm4     \n\t"
  1124.                   "movq      %%mm4, (%%edi)   \n\t"
  1125.  
  1126.                   "movq      8(%%esi), %%mm5  \n\t"
  1127.                   "pand      %%mm1, %%mm5     \n\t"
  1128.                   "movq      %%mm1, %%mm7     \n\t"
  1129.                   "movq      8(%%edi), %%mm6  \n\t"
  1130.                   "pandn     %%mm6, %%mm7     \n\t"
  1131.                   "por       %%mm7, %%mm5     \n\t"
  1132.                   "movq      %%mm5, 8(%%edi)  \n\t"
  1133.  
  1134.                   "movq      16(%%esi), %%mm6 \n\t"
  1135.                   "pand      %%mm2, %%mm6     \n\t"
  1136.                   "movq      %%mm2, %%mm4     \n\t"
  1137.                   "movq      16(%%edi), %%mm7 \n\t"
  1138.                   "pandn     %%mm7, %%mm4     \n\t"
  1139.                   "por       %%mm4, %%mm6     \n\t"
  1140.                   "movq      %%mm6, 16(%%edi) \n\t"
  1141.  
  1142.                   "movq      24(%%esi), %%mm7 \n\t"
  1143.                   "pand      %%mm3, %%mm7     \n\t"
  1144.                   "movq      %%mm3, %%mm5     \n\t"
  1145.                   "movq      24(%%edi), %%mm4 \n\t"
  1146.                   "pandn     %%mm4, %%mm5     \n\t"
  1147.                   "por       %%mm5, %%mm7     \n\t"
  1148.                   "movq      %%mm7, 24(%%edi) \n\t"
  1149.  
  1150.                   "addl      $32, %%esi       \n\t" // inc by 32 bytes processed
  1151.                   "addl      $32, %%edi       \n\t"
  1152.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  1153.                   "ja        mainloop32       \n\t"
  1154.  
  1155.                 "mainloop32end:               \n\t"
  1156. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  1157.                   "movl      %%eax, %%ecx     \n\t"
  1158.                   "cmpl      $0, %%ecx        \n\t"
  1159.                   "jz        end32            \n\t"
  1160. // preload        "movl      mask, %%edx      \n\t"
  1161.                   "sall      $24, %%edx       \n\t" // low byte => high byte
  1162.  
  1163.                 "secondloop32:                \n\t"
  1164.                   "sall      %%edx            \n\t" // move high bit to CF
  1165.                   "jnc       skip32           \n\t" // if CF = 0
  1166.                   "movl      (%%esi), %%eax   \n\t"
  1167.                   "movl      %%eax, (%%edi)   \n\t"
  1168.  
  1169.                 "skip32:                      \n\t"
  1170.                   "addl      $4, %%esi        \n\t"
  1171.                   "addl      $4, %%edi        \n\t"
  1172.                   "decl      %%ecx            \n\t"
  1173.                   "jnz       secondloop32     \n\t"
  1174.  
  1175.                 "end32:                       \n\t"
  1176.                   "EMMS                       \n\t" // DONE
  1177.  
  1178.                   : "=a" (dummy_value_a),           // output regs (dummy)
  1179.                     "=d" (dummy_value_d),
  1180.                     "=c" (dummy_value_c),
  1181.                     "=S" (dummy_value_S),
  1182.                     "=D" (dummy_value_D)
  1183.  
  1184.                   : "3" (srcptr),      // esi       // input regs
  1185.                     "4" (dstptr),      // edi
  1186.                     "0" (diff),        // eax
  1187. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  1188.                     "2" (len),         // ecx
  1189.                     "1" (mask)         // edx
  1190.  
  1191. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1192.                   : "%mm0", "%mm1", "%mm2", "%mm3"  // clobber list
  1193.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  1194. #endif
  1195.                );
  1196.             }
  1197.             else /* mmx _not supported - Use modified C routine */
  1198. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  1199.             {
  1200.                register png_uint_32 i;
  1201.                png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass];
  1202.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1203.                register int stride = BPP4 * png_pass_inc[png_ptr->pass];
  1204.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1205.                register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass];
  1206.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1207.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1208.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  1209.                register png_uint_32 final_val = BPP4 * len;   /* GRR bugfix */
  1210.  
  1211.                srcptr = png_ptr->row_buf + 1 + initial_val;
  1212.                dstptr = row + initial_val;
  1213.  
  1214.                for (i = initial_val; i < final_val; i += stride)
  1215.                {
  1216.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1217.                   srcptr += stride;
  1218.                   dstptr += stride;
  1219.                }
  1220.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  1221.                {
  1222.                   final_val+=diff*BPP4;
  1223.                   for (; i < final_val; i += stride)
  1224.                   {
  1225.                      if (rep_bytes > (int)(final_val-i))
  1226.                         rep_bytes = (int)(final_val-i);
  1227.                      png_memcpy(dstptr, srcptr, rep_bytes);
  1228.                      srcptr += stride;
  1229.                      dstptr += stride;
  1230.                   }
  1231.                }
  1232.             } /* end of else (_mmx_supported) */
  1233.  
  1234.             break;
  1235.          }       /* end 32 bpp */
  1236.  
  1237.          case 48:       /* png_ptr->row_info.pixel_depth */
  1238.          {
  1239.             png_bytep srcptr;
  1240.             png_bytep dstptr;
  1241.  
  1242. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  1243. #if !defined(PNG_1_0_X)
  1244.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
  1245.                 /* && _mmx_supported */ )
  1246. #else
  1247.             if (_mmx_supported)
  1248. #endif
  1249.             {
  1250.                png_uint_32 len;
  1251.                int diff;
  1252.                int dummy_value_a;   // fix 'forbidden register spilled' error
  1253.                int dummy_value_d;
  1254.                int dummy_value_c;
  1255.                int dummy_value_S;
  1256.                int dummy_value_D;
  1257.                _unmask = ~mask;            // global variable for -fPIC version
  1258.                srcptr = png_ptr->row_buf + 1;
  1259.                dstptr = row;
  1260.                len  = png_ptr->width &~7;  // reduce to multiple of 8
  1261.                diff = (int) (png_ptr->width & 7); // amount lost //
  1262.  
  1263.                __asm__ __volatile__ (
  1264.                   "movd      _unmask, %%mm7   \n\t" // load bit pattern
  1265.                   "psubb     %%mm6, %%mm6     \n\t" // zero mm6
  1266.                   "punpcklbw %%mm7, %%mm7     \n\t"
  1267.                   "punpcklwd %%mm7, %%mm7     \n\t"
  1268.                   "punpckldq %%mm7, %%mm7     \n\t" // fill reg with 8 masks
  1269.  
  1270.                   "movq      _mask48_0, %%mm0 \n\t"
  1271.                   "movq      _mask48_1, %%mm1 \n\t"
  1272.                   "movq      _mask48_2, %%mm2 \n\t"
  1273.                   "movq      _mask48_3, %%mm3 \n\t"
  1274.                   "movq      _mask48_4, %%mm4 \n\t"
  1275.                   "movq      _mask48_5, %%mm5 \n\t"
  1276.  
  1277.                   "pand      %%mm7, %%mm0     \n\t"
  1278.                   "pand      %%mm7, %%mm1     \n\t"
  1279.                   "pand      %%mm7, %%mm2     \n\t"
  1280.                   "pand      %%mm7, %%mm3     \n\t"
  1281.                   "pand      %%mm7, %%mm4     \n\t"
  1282.                   "pand      %%mm7, %%mm5     \n\t"
  1283.  
  1284.                   "pcmpeqb   %%mm6, %%mm0     \n\t"
  1285.                   "pcmpeqb   %%mm6, %%mm1     \n\t"
  1286.                   "pcmpeqb   %%mm6, %%mm2     \n\t"
  1287.                   "pcmpeqb   %%mm6, %%mm3     \n\t"
  1288.                   "pcmpeqb   %%mm6, %%mm4     \n\t"
  1289.                   "pcmpeqb   %%mm6, %%mm5     \n\t"
  1290.  
  1291. // preload        "movl      len, %%ecx       \n\t" // load length of line
  1292. // preload        "movl      srcptr, %%esi    \n\t" // load source
  1293. // preload        "movl      dstptr, %%edi    \n\t" // load dest
  1294.  
  1295.                   "cmpl      $0, %%ecx        \n\t"
  1296.                   "jz        mainloop48end    \n\t"
  1297.  
  1298.                 "mainloop48:                  \n\t"
  1299.                   "movq      (%%esi), %%mm7   \n\t"
  1300.                   "pand      %%mm0, %%mm7     \n\t"
  1301.                   "movq      %%mm0, %%mm6     \n\t"
  1302.                   "pandn     (%%edi), %%mm6   \n\t"
  1303.                   "por       %%mm6, %%mm7     \n\t"
  1304.                   "movq      %%mm7, (%%edi)   \n\t"
  1305.  
  1306.                   "movq      8(%%esi), %%mm6  \n\t"
  1307.                   "pand      %%mm1, %%mm6     \n\t"
  1308.                   "movq      %%mm1, %%mm7     \n\t"
  1309.                   "pandn     8(%%edi), %%mm7  \n\t"
  1310.                   "por       %%mm7, %%mm6     \n\t"
  1311.                   "movq      %%mm6, 8(%%edi)  \n\t"
  1312.  
  1313.                   "movq      16(%%esi), %%mm6 \n\t"
  1314.                   "pand      %%mm2, %%mm6     \n\t"
  1315.                   "movq      %%mm2, %%mm7     \n\t"
  1316.                   "pandn     16(%%edi), %%mm7 \n\t"
  1317.                   "por       %%mm7, %%mm6     \n\t"
  1318.                   "movq      %%mm6, 16(%%edi) \n\t"
  1319.  
  1320.                   "movq      24(%%esi), %%mm7 \n\t"
  1321.                   "pand      %%mm3, %%mm7     \n\t"
  1322.                   "movq      %%mm3, %%mm6     \n\t"
  1323.                   "pandn     24(%%edi), %%mm6 \n\t"
  1324.                   "por       %%mm6, %%mm7     \n\t"
  1325.                   "movq      %%mm7, 24(%%edi) \n\t"
  1326.  
  1327.                   "movq      32(%%esi), %%mm6 \n\t"
  1328.                   "pand      %%mm4, %%mm6     \n\t"
  1329.                   "movq      %%mm4, %%mm7     \n\t"
  1330.                   "pandn     32(%%edi), %%mm7 \n\t"
  1331.                   "por       %%mm7, %%mm6     \n\t"
  1332.                   "movq      %%mm6, 32(%%edi) \n\t"
  1333.  
  1334.                   "movq      40(%%esi), %%mm7 \n\t"
  1335.                   "pand      %%mm5, %%mm7     \n\t"
  1336.                   "movq      %%mm5, %%mm6     \n\t"
  1337.                   "pandn     40(%%edi), %%mm6 \n\t"
  1338.                   "por       %%mm6, %%mm7     \n\t"
  1339.                   "movq      %%mm7, 40(%%edi) \n\t"
  1340.  
  1341.                   "addl      $48, %%esi       \n\t" // inc by 48 bytes processed
  1342.                   "addl      $48, %%edi       \n\t"
  1343.                   "subl      $8, %%ecx        \n\t" // dec by 8 pixels processed
  1344.  
  1345.                   "ja        mainloop48       \n\t"
  1346.  
  1347.                 "mainloop48end:               \n\t"
  1348. // preload        "movl      diff, %%ecx      \n\t" // (diff is in eax)
  1349.                   "movl      %%eax, %%ecx     \n\t"
  1350.                   "cmpl      $0, %%ecx        \n\t"
  1351.                   "jz        end48            \n\t"
  1352. // preload        "movl      mask, %%edx      \n\t"
  1353.                   "sall      $24, %%edx       \n\t" // make low byte, high byte
  1354.  
  1355.                 "secondloop48:                \n\t"
  1356.                   "sall      %%edx            \n\t" // move high bit to CF
  1357.                   "jnc       skip48           \n\t" // if CF = 0
  1358.                   "movl      (%%esi), %%eax   \n\t"
  1359.                   "movl      %%eax, (%%edi)   \n\t"
  1360.  
  1361.                 "skip48:                      \n\t"
  1362.                   "addl      $4, %%esi        \n\t"
  1363.                   "addl      $4, %%edi        \n\t"
  1364.                   "decl      %%ecx            \n\t"
  1365.                   "jnz       secondloop48     \n\t"
  1366.  
  1367.                 "end48:                       \n\t"
  1368.                   "EMMS                       \n\t" // DONE
  1369.  
  1370.                   : "=a" (dummy_value_a),           // output regs (dummy)
  1371.                     "=d" (dummy_value_d),
  1372.                     "=c" (dummy_value_c),
  1373.                     "=S" (dummy_value_S),
  1374.                     "=D" (dummy_value_D)
  1375.  
  1376.                   : "3" (srcptr),      // esi       // input regs
  1377.                     "4" (dstptr),      // edi
  1378.                     "0" (diff),        // eax
  1379. // was (unmask)     "b"    RESERVED    // ebx       // Global Offset Table idx
  1380.                     "2" (len),         // ecx
  1381.                     "1" (mask)         // edx
  1382.  
  1383. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  1384.                   : "%mm0", "%mm1", "%mm2", "%mm3"  // clobber list
  1385.                   , "%mm4", "%mm5", "%mm6", "%mm7"
  1386. #endif
  1387.                );
  1388.             }
  1389.             else /* mmx _not supported - Use modified C routine */
  1390. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  1391.             {
  1392.                register png_uint_32 i;
  1393.                png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass];
  1394.                  /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1395.                register int stride = BPP6 * png_pass_inc[png_ptr->pass];
  1396.                  /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1397.                register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass];
  1398.                  /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1399.                png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1400.                int diff = (int) (png_ptr->width & 7); /* amount lost */
  1401.                register png_uint_32 final_val = BPP6 * len;   /* GRR bugfix */
  1402.  
  1403.                srcptr = png_ptr->row_buf + 1 + initial_val;
  1404.                dstptr = row + initial_val;
  1405.  
  1406.                for (i = initial_val; i < final_val; i += stride)
  1407.                {
  1408.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1409.                   srcptr += stride;
  1410.                   dstptr += stride;
  1411.                }
  1412.                if (diff)  /* number of leftover pixels:  3 for pngtest */
  1413.                {
  1414.                   final_val+=diff*BPP6;
  1415.                   for (; i < final_val; i += stride)
  1416.                   {
  1417.                      if (rep_bytes > (int)(final_val-i))
  1418.                         rep_bytes = (int)(final_val-i);
  1419.                      png_memcpy(dstptr, srcptr, rep_bytes);
  1420.                      srcptr += stride;
  1421.                      dstptr += stride;
  1422.                   }
  1423.                }
  1424.             } /* end of else (_mmx_supported) */
  1425.  
  1426.             break;
  1427.          }       /* end 48 bpp */
  1428.  
  1429.          case 64:       /* png_ptr->row_info.pixel_depth */
  1430.          {
  1431.             png_bytep srcptr;
  1432.             png_bytep dstptr;
  1433.             register png_uint_32 i;
  1434.             png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass];
  1435.               /* png.c:  png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
  1436.             register int stride = BPP8 * png_pass_inc[png_ptr->pass];
  1437.               /* png.c:  png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
  1438.             register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass];
  1439.               /* png.c:  png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
  1440.             png_uint_32 len = png_ptr->width &~7;  /* reduce to mult. of 8 */
  1441.             int diff = (int) (png_ptr->width & 7); /* amount lost */
  1442.             register png_uint_32 final_val = BPP8 * len;   /* GRR bugfix */
  1443.  
  1444.             srcptr = png_ptr->row_buf + 1 + initial_val;
  1445.             dstptr = row + initial_val;
  1446.  
  1447.             for (i = initial_val; i < final_val; i += stride)
  1448.             {
  1449.                png_memcpy(dstptr, srcptr, rep_bytes);
  1450.                srcptr += stride;
  1451.                dstptr += stride;
  1452.             }
  1453.             if (diff)  /* number of leftover pixels:  3 for pngtest */
  1454.             {
  1455.                final_val+=diff*BPP8;
  1456.                for (; i < final_val; i += stride)
  1457.                {
  1458.                   if (rep_bytes > (int)(final_val-i))
  1459.                      rep_bytes = (int)(final_val-i);
  1460.                   png_memcpy(dstptr, srcptr, rep_bytes);
  1461.                   srcptr += stride;
  1462.                   dstptr += stride;
  1463.                }
  1464.             }
  1465.  
  1466.             break;
  1467.          }       /* end 64 bpp */
  1468.  
  1469.          default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */
  1470.          {
  1471.             /* this should never happen */
  1472.             png_warning(png_ptr, "Invalid row_info.pixel_depth in pnggccrd");
  1473.             break;
  1474.          }
  1475.       } /* end switch (png_ptr->row_info.pixel_depth) */
  1476.  
  1477.    } /* end if (non-trivial mask) */
  1478.  
  1479. } /* end png_combine_row() */
  1480.  
  1481. #endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */
  1482.  
  1483.  
  1484.  
  1485.  
  1486. /*===========================================================================*/
  1487. /*                                                                           */
  1488. /*                 P N G _ D O _ R E A D _ I N T E R L A C E                 */
  1489. /*                                                                           */
  1490. /*===========================================================================*/
  1491.  
  1492. #if defined(PNG_READ_INTERLACING_SUPPORTED)
  1493. #if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE)
  1494.  
  1495. /* png_do_read_interlace() is called after any 16-bit to 8-bit conversion
  1496.  * has taken place.  [GRR: what other steps come before and/or after?]
  1497.  */
  1498.  
  1499. void /* PRIVATE */
  1500. png_do_read_interlace(png_structp png_ptr)
  1501. {
  1502.    png_row_infop row_info = &(png_ptr->row_info);
  1503.    png_bytep row = png_ptr->row_buf + 1;
  1504.    int pass = png_ptr->pass;
  1505. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1506.    png_uint_32 transformations = png_ptr->transformations;
  1507. #endif
  1508.  
  1509.    png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n");
  1510.  
  1511. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  1512.    if (_mmx_supported == 2) {
  1513. #if !defined(PNG_1_0_X)
  1514.        /* this should have happened in png_init_mmx_flags() already */
  1515.        png_warning(png_ptr, "asm_flags may not have been initialized");
  1516. #endif
  1517.        png_mmx_support();
  1518.    }
  1519. #endif
  1520.  
  1521.    if (row != NULL && row_info != NULL)
  1522.    {
  1523.       png_uint_32 final_width;
  1524.  
  1525.       final_width = row_info->width * png_pass_inc[pass];
  1526.  
  1527.       switch (row_info->pixel_depth)
  1528.       {
  1529.          case 1:
  1530.          {
  1531.             png_bytep sp, dp;
  1532.             int sshift, dshift;
  1533.             int s_start, s_end, s_inc;
  1534.             png_byte v;
  1535.             png_uint_32 i;
  1536.             int j;
  1537.  
  1538.             sp = row + (png_size_t)((row_info->width - 1) >> 3);
  1539.             dp = row + (png_size_t)((final_width - 1) >> 3);
  1540. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1541.             if (transformations & PNG_PACKSWAP)
  1542.             {
  1543.                sshift = (int)((row_info->width + 7) & 7);
  1544.                dshift = (int)((final_width + 7) & 7);
  1545.                s_start = 7;
  1546.                s_end = 0;
  1547.                s_inc = -1;
  1548.             }
  1549.             else
  1550. #endif
  1551.             {
  1552.                sshift = 7 - (int)((row_info->width + 7) & 7);
  1553.                dshift = 7 - (int)((final_width + 7) & 7);
  1554.                s_start = 0;
  1555.                s_end = 7;
  1556.                s_inc = 1;
  1557.             }
  1558.  
  1559.             for (i = row_info->width; i; i--)
  1560.             {
  1561.                v = (png_byte)((*sp >> sshift) & 0x1);
  1562.                for (j = 0; j < png_pass_inc[pass]; j++)
  1563.                {
  1564.                   *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
  1565.                   *dp |= (png_byte)(v << dshift);
  1566.                   if (dshift == s_end)
  1567.                   {
  1568.                      dshift = s_start;
  1569.                      dp--;
  1570.                   }
  1571.                   else
  1572.                      dshift += s_inc;
  1573.                }
  1574.                if (sshift == s_end)
  1575.                {
  1576.                   sshift = s_start;
  1577.                   sp--;
  1578.                }
  1579.                else
  1580.                   sshift += s_inc;
  1581.             }
  1582.             break;
  1583.          }
  1584.  
  1585.          case 2:
  1586.          {
  1587.             png_bytep sp, dp;
  1588.             int sshift, dshift;
  1589.             int s_start, s_end, s_inc;
  1590.             png_uint_32 i;
  1591.  
  1592.             sp = row + (png_size_t)((row_info->width - 1) >> 2);
  1593.             dp = row + (png_size_t)((final_width - 1) >> 2);
  1594. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1595.             if (transformations & PNG_PACKSWAP)
  1596.             {
  1597.                sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
  1598.                dshift = (png_size_t)(((final_width + 3) & 3) << 1);
  1599.                s_start = 6;
  1600.                s_end = 0;
  1601.                s_inc = -2;
  1602.             }
  1603.             else
  1604. #endif
  1605.             {
  1606.                sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
  1607.                dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
  1608.                s_start = 0;
  1609.                s_end = 6;
  1610.                s_inc = 2;
  1611.             }
  1612.  
  1613.             for (i = row_info->width; i; i--)
  1614.             {
  1615.                png_byte v;
  1616.                int j;
  1617.  
  1618.                v = (png_byte)((*sp >> sshift) & 0x3);
  1619.                for (j = 0; j < png_pass_inc[pass]; j++)
  1620.                {
  1621.                   *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
  1622.                   *dp |= (png_byte)(v << dshift);
  1623.                   if (dshift == s_end)
  1624.                   {
  1625.                      dshift = s_start;
  1626.                      dp--;
  1627.                   }
  1628.                   else
  1629.                      dshift += s_inc;
  1630.                }
  1631.                if (sshift == s_end)
  1632.                {
  1633.                   sshift = s_start;
  1634.                   sp--;
  1635.                }
  1636.                else
  1637.                   sshift += s_inc;
  1638.             }
  1639.             break;
  1640.          }
  1641.  
  1642.          case 4:
  1643.          {
  1644.             png_bytep sp, dp;
  1645.             int sshift, dshift;
  1646.             int s_start, s_end, s_inc;
  1647.             png_uint_32 i;
  1648.  
  1649.             sp = row + (png_size_t)((row_info->width - 1) >> 1);
  1650.             dp = row + (png_size_t)((final_width - 1) >> 1);
  1651. #if defined(PNG_READ_PACKSWAP_SUPPORTED)
  1652.             if (transformations & PNG_PACKSWAP)
  1653.             {
  1654.                sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
  1655.                dshift = (png_size_t)(((final_width + 1) & 1) << 2);
  1656.                s_start = 4;
  1657.                s_end = 0;
  1658.                s_inc = -4;
  1659.             }
  1660.             else
  1661. #endif
  1662.             {
  1663.                sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
  1664.                dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
  1665.                s_start = 0;
  1666.                s_end = 4;
  1667.                s_inc = 4;
  1668.             }
  1669.  
  1670.             for (i = row_info->width; i; i--)
  1671.             {
  1672.                png_byte v;
  1673.                int j;
  1674.  
  1675.                v = (png_byte)((*sp >> sshift) & 0xf);
  1676.                for (j = 0; j < png_pass_inc[pass]; j++)
  1677.                {
  1678.                   *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
  1679.                   *dp |= (png_byte)(v << dshift);
  1680.                   if (dshift == s_end)
  1681.                   {
  1682.                      dshift = s_start;
  1683.                      dp--;
  1684.                   }
  1685.                   else
  1686.                      dshift += s_inc;
  1687.                }
  1688.                if (sshift == s_end)
  1689.                {
  1690.                   sshift = s_start;
  1691.                   sp--;
  1692.                }
  1693.                else
  1694.                   sshift += s_inc;
  1695.             }
  1696.             break;
  1697.          }
  1698.  
  1699.        /*====================================================================*/
  1700.  
  1701.          default: /* 8-bit or larger (this is where the routine is modified) */
  1702.          {
  1703. #if 0
  1704. //          static unsigned long long _const4 = 0x0000000000FFFFFFLL;  no good
  1705. //          static unsigned long long const4 = 0x0000000000FFFFFFLL;   no good
  1706. //          unsigned long long _const4 = 0x0000000000FFFFFFLL;         no good
  1707. //          unsigned long long const4 = 0x0000000000FFFFFFLL;          no good
  1708. #endif
  1709.             png_bytep sptr, dp;
  1710.             png_uint_32 i;
  1711.             png_size_t pixel_bytes;
  1712.             int width = (int)row_info->width;
  1713.  
  1714.             pixel_bytes = (row_info->pixel_depth >> 3);
  1715.  
  1716.             /* point sptr at the last pixel in the pre-expanded row: */
  1717.             sptr = row + (width - 1) * pixel_bytes;
  1718.  
  1719.             /* point dp at the last pixel position in the expanded row: */
  1720.             dp = row + (final_width - 1) * pixel_bytes;
  1721.  
  1722.             /* New code by Nirav Chhatrapati - Intel Corporation */
  1723.  
  1724. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  1725. #if !defined(PNG_1_0_X)
  1726.             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
  1727.                 /* && _mmx_supported */ )
  1728. #else
  1729.             if (_mmx_supported)
  1730. #endif
  1731.             {
  1732.                //--------------------------------------------------------------
  1733.                if (pixel_bytes == 3)
  1734.                {
  1735.                   if (((pass == 0) || (pass == 1)) && width)
  1736.                   {
  1737.                      int dummy_value_c;   // fix 'forbidden register spilled'
  1738.                      int dummy_value_S;
  1739.                      int dummy_value_D;
  1740.  
  1741.                      __asm__ __volatile__ (
  1742.                         "subl $21, %%edi         \n\t"
  1743.                                      // (png_pass_inc[pass] - 1)*pixel_bytes
  1744.  
  1745.                      ".loop3_pass0:              \n\t"
  1746.                         "movd (%%esi), %%mm0     \n\t" // x x x x x 2 1 0
  1747.                         "pand _const4, %%mm0     \n\t" // z z z z z 2 1 0
  1748.                         "movq %%mm0, %%mm1       \n\t" // z z z z z 2 1 0
  1749.                         "psllq $16, %%mm0        \n\t" // z z z 2 1 0 z z
  1750.                         "movq %%mm0, %%mm2       \n\t" // z z z 2 1 0 z z
  1751.                         "psllq $24, %%mm0        \n\t" // 2 1 0 z z z z z
  1752.                         "psrlq $8, %%mm1         \n\t" // z z z z z z 2 1
  1753.                         "por %%mm2, %%mm0        \n\t" // 2 1 0 2 1 0 z z
  1754.                         "por %%mm1, %%mm0        \n\t" // 2 1 0 2 1 0 2 1
  1755.                         "movq %%mm0, %%mm3       \n\t" // 2 1 0 2 1 0 2 1
  1756.                         "psllq $16, %%mm0        \n\t" // 0 2 1 0 2 1 z z
  1757.                         "movq %%mm3, %%mm4       \n\t" // 2 1 0 2 1 0 2 1
  1758.                         "punpckhdq %%mm0, %%mm3  \n\t" // 0 2 1 0 2 1 0 2
  1759.                         "movq %%mm4, 16(%%edi)   \n\t"
  1760.                         "psrlq $32, %%mm0        \n\t" // z z z z 0 2 1 0
  1761.                         "movq %%mm3, 8(%%edi)    \n\t"
  1762.                         "punpckldq %%mm4, %%mm0  \n\t" // 1 0 2 1 0 2 1 0
  1763.                         "subl $3, %%esi          \n\t"
  1764.                         "movq %%mm0, (%%edi)     \n\t"
  1765.                         "subl $24, %%edi         \n\t"
  1766.                         "decl %%ecx              \n\t"
  1767.                         "jnz .loop3_pass0        \n\t"
  1768.                         "EMMS                    \n\t" // DONE
  1769.  
  1770.                         : "=c" (dummy_value_c),        // output regs (dummy)
  1771.                           "=S" (dummy_value_S),
  1772.                           "=D" (dummy_value_D)
  1773.  
  1774.                         : "1" (sptr),      // esi      // input regs
  1775.                           "2" (dp),        // edi
  1776.                           "0" (width),     // ecx
  1777.                           "rim" (_const4)  // %1(?)  (0x0000000000FFFFFFLL)
  1778.  
  1779. #if 0  /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1780.                         : "%mm0", "%mm1", "%mm2"       // clobber list
  1781.                         , "%mm3", "%mm4"
  1782. #endif
  1783.                      );
  1784.                   }
  1785.                   else if (((pass == 2) || (pass == 3)) && width)
  1786.                   {
  1787.                      int dummy_value_c;   // fix 'forbidden register spilled'
  1788.                      int dummy_value_S;
  1789.                      int dummy_value_D;
  1790.  
  1791.                      __asm__ __volatile__ (
  1792.                         "subl $9, %%edi          \n\t"
  1793.                                      // (png_pass_inc[pass] - 1)*pixel_bytes
  1794.  
  1795.                      ".loop3_pass2:              \n\t"
  1796.                         "movd (%%esi), %%mm0     \n\t" // x x x x x 2 1 0
  1797.                         "pand _const4, %%mm0     \n\t" // z z z z z 2 1 0
  1798.                         "movq %%mm0, %%mm1       \n\t" // z z z z z 2 1 0
  1799.                         "psllq $16, %%mm0        \n\t" // z z z 2 1 0 z z
  1800.                         "movq %%mm0, %%mm2       \n\t" // z z z 2 1 0 z z
  1801.                         "psllq $24, %%mm0        \n\t" // 2 1 0 z z z z z
  1802.                         "psrlq $8, %%mm1         \n\t" // z z z z z z 2 1
  1803.                         "por %%mm2, %%mm0        \n\t" // 2 1 0 2 1 0 z z
  1804.                         "por %%mm1, %%mm0        \n\t" // 2 1 0 2 1 0 2 1
  1805.                         "movq %%mm0, 4(%%edi)    \n\t"
  1806.                         "psrlq $16, %%mm0        \n\t" // z z 2 1 0 2 1 0
  1807.                         "subl $3, %%esi          \n\t"
  1808.                         "movd %%mm0, (%%edi)     \n\t"
  1809.                         "subl $12, %%edi         \n\t"
  1810.                         "decl %%ecx              \n\t"
  1811.                         "jnz .loop3_pass2        \n\t"
  1812.                         "EMMS                    \n\t" // DONE
  1813.  
  1814.                         : "=c" (dummy_value_c),        // output regs (dummy)
  1815.                           "=S" (dummy_value_S),
  1816.                           "=D" (dummy_value_D)
  1817.  
  1818.                         : "1" (sptr),      // esi      // input regs
  1819.                           "2" (dp),        // edi
  1820.                           "0" (width),     // ecx
  1821.                           "rim" (_const4)  // (0x0000000000FFFFFFLL)
  1822.  
  1823. #if 0  /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1824.                         : "%mm0", "%mm1", "%mm2"       // clobber list
  1825. #endif
  1826.                      );
  1827.                   }
  1828.                   else if (width) /* && ((pass == 4) || (pass == 5)) */
  1829.                   {
  1830.                      int width_mmx = ((width >> 1) << 1) - 8;   // GRR:  huh?
  1831.                      if (width_mmx < 0)
  1832.                          width_mmx = 0;
  1833.                      width -= width_mmx;        // 8 or 9 pix, 24 or 27 bytes
  1834.                      if (width_mmx)
  1835.                      {
  1836.                         // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
  1837.                         // sptr points at last pixel in pre-expanded row
  1838.                         // dp points at last pixel position in expanded row
  1839.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1840.                         int dummy_value_S;
  1841.                         int dummy_value_D;
  1842.  
  1843.                         __asm__ __volatile__ (
  1844.                            "subl $3, %%esi          \n\t"
  1845.                            "subl $9, %%edi          \n\t"
  1846.                                         // (png_pass_inc[pass] + 1)*pixel_bytes
  1847.  
  1848.                         ".loop3_pass4:              \n\t"
  1849.                            "movq (%%esi), %%mm0     \n\t" // x x 5 4 3 2 1 0
  1850.                            "movq %%mm0, %%mm1       \n\t" // x x 5 4 3 2 1 0
  1851.                            "movq %%mm0, %%mm2       \n\t" // x x 5 4 3 2 1 0
  1852.                            "psllq $24, %%mm0        \n\t" // 4 3 2 1 0 z z z
  1853.                            "pand _const4, %%mm1     \n\t" // z z z z z 2 1 0
  1854.                            "psrlq $24, %%mm2        \n\t" // z z z x x 5 4 3
  1855.                            "por %%mm1, %%mm0        \n\t" // 4 3 2 1 0 2 1 0
  1856.                            "movq %%mm2, %%mm3       \n\t" // z z z x x 5 4 3
  1857.                            "psllq $8, %%mm2         \n\t" // z z x x 5 4 3 z
  1858.                            "movq %%mm0, (%%edi)     \n\t"
  1859.                            "psrlq $16, %%mm3        \n\t" // z z z z z x x 5
  1860.                            "pand _const6, %%mm3     \n\t" // z z z z z z z 5
  1861.                            "por %%mm3, %%mm2        \n\t" // z z x x 5 4 3 5
  1862.                            "subl $6, %%esi          \n\t"
  1863.                            "movd %%mm2, 8(%%edi)    \n\t"
  1864.                            "subl $12, %%edi         \n\t"
  1865.                            "subl $2, %%ecx          \n\t"
  1866.                            "jnz .loop3_pass4        \n\t"
  1867.                            "EMMS                    \n\t" // DONE
  1868.  
  1869.                            : "=c" (dummy_value_c),        // output regs (dummy)
  1870.                              "=S" (dummy_value_S),
  1871.                              "=D" (dummy_value_D)
  1872.  
  1873.                            : "1" (sptr),      // esi      // input regs
  1874.                              "2" (dp),        // edi
  1875.                              "0" (width_mmx), // ecx
  1876.                              "rim" (_const4), // 0x0000000000FFFFFFLL
  1877.                              "rim" (_const6)  // 0x00000000000000FFLL
  1878.  
  1879. #if 0  /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1880.                            : "%mm0", "%mm1"               // clobber list
  1881.                            , "%mm2", "%mm3"
  1882. #endif
  1883.                         );
  1884.                      }
  1885.  
  1886.                      sptr -= width_mmx*3;
  1887.                      dp -= width_mmx*6;
  1888.                      for (i = width; i; i--)
  1889.                      {
  1890.                         png_byte v[8];
  1891.                         int j;
  1892.  
  1893.                         png_memcpy(v, sptr, 3);
  1894.                         for (j = 0; j < png_pass_inc[pass]; j++)
  1895.                         {
  1896.                            png_memcpy(dp, v, 3);
  1897.                            dp -= 3;
  1898.                         }
  1899.                         sptr -= 3;
  1900.                      }
  1901.                   }
  1902.                } /* end of pixel_bytes == 3 */
  1903.  
  1904.                //--------------------------------------------------------------
  1905.                else if (pixel_bytes == 1)
  1906.                {
  1907.                   if (((pass == 0) || (pass == 1)) && width)
  1908.                   {
  1909.                      int width_mmx = ((width >> 2) << 2);
  1910.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  1911.                      if (width_mmx)
  1912.                      {
  1913.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1914.                         int dummy_value_S;
  1915.                         int dummy_value_D;
  1916.  
  1917.                         __asm__ __volatile__ (
  1918.                            "subl $3, %%esi          \n\t"
  1919.                            "subl $31, %%edi         \n\t"
  1920.  
  1921.                         ".loop1_pass0:              \n\t"
  1922.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  1923.                            "movq %%mm0, %%mm1       \n\t" // x x x x 3 2 1 0
  1924.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  1925.                            "movq %%mm0, %%mm2       \n\t" // 3 3 2 2 1 1 0 0
  1926.                            "punpcklwd %%mm0, %%mm0  \n\t" // 1 1 1 1 0 0 0 0
  1927.                            "movq %%mm0, %%mm3       \n\t" // 1 1 1 1 0 0 0 0
  1928.                            "punpckldq %%mm0, %%mm0  \n\t" // 0 0 0 0 0 0 0 0
  1929.                            "punpckhdq %%mm3, %%mm3  \n\t" // 1 1 1 1 1 1 1 1
  1930.                            "movq %%mm0, (%%edi)     \n\t"
  1931.                            "punpckhwd %%mm2, %%mm2  \n\t" // 3 3 3 3 2 2 2 2
  1932.                            "movq %%mm3, 8(%%edi)    \n\t"
  1933.                            "movq %%mm2, %%mm4       \n\t" // 3 3 3 3 2 2 2 2
  1934.                            "punpckldq %%mm2, %%mm2  \n\t" // 2 2 2 2 2 2 2 2
  1935.                            "punpckhdq %%mm4, %%mm4  \n\t" // 3 3 3 3 3 3 3 3
  1936.                            "movq %%mm2, 16(%%edi)   \n\t"
  1937.                            "subl $4, %%esi          \n\t"
  1938.                            "movq %%mm4, 24(%%edi)   \n\t"
  1939.                            "subl $32, %%edi         \n\t"
  1940.                            "subl $4, %%ecx          \n\t"
  1941.                            "jnz .loop1_pass0        \n\t"
  1942.                            "EMMS                    \n\t" // DONE
  1943.  
  1944.                            : "=c" (dummy_value_c),        // output regs (dummy)
  1945.                              "=S" (dummy_value_S),
  1946.                              "=D" (dummy_value_D)
  1947.  
  1948.                            : "1" (sptr),      // esi      // input regs
  1949.                              "2" (dp),        // edi
  1950.                              "0" (width_mmx)  // ecx
  1951.  
  1952. #if 0  /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */
  1953.                            : "%mm0", "%mm1", "%mm2"       // clobber list
  1954.                            , "%mm3", "%mm4"
  1955. #endif
  1956.                         );
  1957.                      }
  1958.  
  1959.                      sptr -= width_mmx;
  1960.                      dp -= width_mmx*8;
  1961.                      for (i = width; i; i--)
  1962.                      {
  1963.                         int j;
  1964.  
  1965.                        /* I simplified this part in version 1.0.4e
  1966.                         * here and in several other instances where
  1967.                         * pixel_bytes == 1  -- GR-P
  1968.                         *
  1969.                         * Original code:
  1970.                         *
  1971.                         * png_byte v[8];
  1972.                         * png_memcpy(v, sptr, pixel_bytes);
  1973.                         * for (j = 0; j < png_pass_inc[pass]; j++)
  1974.                         * {
  1975.                         *    png_memcpy(dp, v, pixel_bytes);
  1976.                         *    dp -= pixel_bytes;
  1977.                         * }
  1978.                         * sptr -= pixel_bytes;
  1979.                         *
  1980.                         * Replacement code is in the next three lines:
  1981.                         */
  1982.  
  1983.                         for (j = 0; j < png_pass_inc[pass]; j++)
  1984.                         {
  1985.                            *dp-- = *sptr;
  1986.                         }
  1987.                         --sptr;
  1988.                      }
  1989.                   }
  1990.                   else if (((pass == 2) || (pass == 3)) && width)
  1991.                   {
  1992.                      int width_mmx = ((width >> 2) << 2);
  1993.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  1994.                      if (width_mmx)
  1995.                      {
  1996.                         int dummy_value_c;  // fix 'forbidden register spilled'
  1997.                         int dummy_value_S;
  1998.                         int dummy_value_D;
  1999.  
  2000.                         __asm__ __volatile__ (
  2001.                            "subl $3, %%esi          \n\t"
  2002.                            "subl $15, %%edi         \n\t"
  2003.  
  2004.                         ".loop1_pass2:              \n\t"
  2005.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2006.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  2007.                            "movq %%mm0, %%mm1       \n\t" // 3 3 2 2 1 1 0 0
  2008.                            "punpcklwd %%mm0, %%mm0  \n\t" // 1 1 1 1 0 0 0 0
  2009.                            "punpckhwd %%mm1, %%mm1  \n\t" // 3 3 3 3 2 2 2 2
  2010.                            "movq %%mm0, (%%edi)     \n\t"
  2011.                            "subl $4, %%esi          \n\t"
  2012.                            "movq %%mm1, 8(%%edi)    \n\t"
  2013.                            "subl $16, %%edi         \n\t"
  2014.                            "subl $4, %%ecx          \n\t"
  2015.                            "jnz .loop1_pass2        \n\t"
  2016.                            "EMMS                    \n\t" // DONE
  2017.  
  2018.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2019.                              "=S" (dummy_value_S),
  2020.                              "=D" (dummy_value_D)
  2021.  
  2022.                            : "1" (sptr),      // esi      // input regs
  2023.                              "2" (dp),        // edi
  2024.                              "0" (width_mmx)  // ecx
  2025.  
  2026. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2027.                            : "%mm0", "%mm1"               // clobber list
  2028. #endif
  2029.                         );
  2030.                      }
  2031.  
  2032.                      sptr -= width_mmx;
  2033.                      dp -= width_mmx*4;
  2034.                      for (i = width; i; i--)
  2035.                      {
  2036.                         int j;
  2037.  
  2038.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2039.                         {
  2040.                            *dp-- = *sptr;
  2041.                         }
  2042.                         --sptr;
  2043.                      }
  2044.                   }
  2045.                   else if (width)  /* && ((pass == 4) || (pass == 5)) */
  2046.                   {
  2047.                      int width_mmx = ((width >> 3) << 3);
  2048.                      width -= width_mmx;        // 0-3 pixels => 0-3 bytes
  2049.                      if (width_mmx)
  2050.                      {
  2051.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2052.                         int dummy_value_S;
  2053.                         int dummy_value_D;
  2054.  
  2055.                         __asm__ __volatile__ (
  2056.                            "subl $7, %%esi          \n\t"
  2057.                            "subl $15, %%edi         \n\t"
  2058.  
  2059.                         ".loop1_pass4:              \n\t"
  2060.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2061.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2062.                            "punpcklbw %%mm0, %%mm0  \n\t" // 3 3 2 2 1 1 0 0
  2063.                            "punpckhbw %%mm1, %%mm1  \n\t" // 7 7 6 6 5 5 4 4
  2064.                            "movq %%mm1, 8(%%edi)    \n\t"
  2065.                            "subl $8, %%esi          \n\t"
  2066.                            "movq %%mm0, (%%edi)     \n\t"
  2067.                            "subl $16, %%edi         \n\t"
  2068.                            "subl $8, %%ecx          \n\t"
  2069.                            "jnz .loop1_pass4        \n\t"
  2070.                            "EMMS                    \n\t" // DONE
  2071.  
  2072.                            : "=c" (dummy_value_c),        // output regs (none)
  2073.                              "=S" (dummy_value_S),
  2074.                              "=D" (dummy_value_D)
  2075.  
  2076.                            : "1" (sptr),      // esi      // input regs
  2077.                              "2" (dp),        // edi
  2078.                              "0" (width_mmx)  // ecx
  2079.  
  2080. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2081.                            : "%mm0", "%mm1"               // clobber list
  2082. #endif
  2083.                         );
  2084.                      }
  2085.  
  2086.                      sptr -= width_mmx;
  2087.                      dp -= width_mmx*2;
  2088.                      for (i = width; i; i--)
  2089.                      {
  2090.                         int j;
  2091.  
  2092.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2093.                         {
  2094.                            *dp-- = *sptr;
  2095.                         }
  2096.                         --sptr;
  2097.                      }
  2098.                   }
  2099.                } /* end of pixel_bytes == 1 */
  2100.  
  2101.                //--------------------------------------------------------------
  2102.                else if (pixel_bytes == 2)
  2103.                {
  2104.                   if (((pass == 0) || (pass == 1)) && width)
  2105.                   {
  2106.                      int width_mmx = ((width >> 1) << 1);
  2107.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2108.                      if (width_mmx)
  2109.                      {
  2110.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2111.                         int dummy_value_S;
  2112.                         int dummy_value_D;
  2113.  
  2114.                         __asm__ __volatile__ (
  2115.                            "subl $2, %%esi          \n\t"
  2116.                            "subl $30, %%edi         \n\t"
  2117.  
  2118.                         ".loop2_pass0:              \n\t"
  2119.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2120.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2121.                            "movq %%mm0, %%mm1       \n\t" // 3 2 3 2 1 0 1 0
  2122.                            "punpckldq %%mm0, %%mm0  \n\t" // 1 0 1 0 1 0 1 0
  2123.                            "punpckhdq %%mm1, %%mm1  \n\t" // 3 2 3 2 3 2 3 2
  2124.                            "movq %%mm0, (%%edi)     \n\t"
  2125.                            "movq %%mm0, 8(%%edi)    \n\t"
  2126.                            "movq %%mm1, 16(%%edi)   \n\t"
  2127.                            "subl $4, %%esi          \n\t"
  2128.                            "movq %%mm1, 24(%%edi)   \n\t"
  2129.                            "subl $32, %%edi         \n\t"
  2130.                            "subl $2, %%ecx          \n\t"
  2131.                            "jnz .loop2_pass0        \n\t"
  2132.                            "EMMS                    \n\t" // DONE
  2133.  
  2134.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2135.                              "=S" (dummy_value_S),
  2136.                              "=D" (dummy_value_D)
  2137.  
  2138.                            : "1" (sptr),      // esi      // input regs
  2139.                              "2" (dp),        // edi
  2140.                              "0" (width_mmx)  // ecx
  2141.  
  2142. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2143.                            : "%mm0", "%mm1"               // clobber list
  2144. #endif
  2145.                         );
  2146.                      }
  2147.  
  2148.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2149.                      dp -= (width_mmx*16 - 2);  // sign fixed
  2150.                      for (i = width; i; i--)
  2151.                      {
  2152.                         png_byte v[8];
  2153.                         int j;
  2154.                         sptr -= 2;
  2155.                         png_memcpy(v, sptr, 2);
  2156.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2157.                         {
  2158.                            dp -= 2;
  2159.                            png_memcpy(dp, v, 2);
  2160.                         }
  2161.                      }
  2162.                   }
  2163.                   else if (((pass == 2) || (pass == 3)) && width)
  2164.                   {
  2165.                      int width_mmx = ((width >> 1) << 1) ;
  2166.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2167.                      if (width_mmx)
  2168.                      {
  2169.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2170.                         int dummy_value_S;
  2171.                         int dummy_value_D;
  2172.  
  2173.                         __asm__ __volatile__ (
  2174.                            "subl $2, %%esi          \n\t"
  2175.                            "subl $14, %%edi         \n\t"
  2176.  
  2177.                         ".loop2_pass2:              \n\t"
  2178.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2179.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2180.                            "movq %%mm0, %%mm1       \n\t" // 3 2 3 2 1 0 1 0
  2181.                            "punpckldq %%mm0, %%mm0  \n\t" // 1 0 1 0 1 0 1 0
  2182.                            "punpckhdq %%mm1, %%mm1  \n\t" // 3 2 3 2 3 2 3 2
  2183.                            "movq %%mm0, (%%edi)     \n\t"
  2184.                            "subl $4, %%esi          \n\t"
  2185.                            "movq %%mm1, 8(%%edi)    \n\t"
  2186.                            "subl $16, %%edi         \n\t"
  2187.                            "subl $2, %%ecx          \n\t"
  2188.                            "jnz .loop2_pass2        \n\t"
  2189.                            "EMMS                    \n\t" // DONE
  2190.  
  2191.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2192.                              "=S" (dummy_value_S),
  2193.                              "=D" (dummy_value_D)
  2194.  
  2195.                            : "1" (sptr),      // esi      // input regs
  2196.                              "2" (dp),        // edi
  2197.                              "0" (width_mmx)  // ecx
  2198.  
  2199. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2200.                            : "%mm0", "%mm1"               // clobber list
  2201. #endif
  2202.                         );
  2203.                      }
  2204.  
  2205.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2206.                      dp -= (width_mmx*8 - 2);   // sign fixed
  2207.                      for (i = width; i; i--)
  2208.                      {
  2209.                         png_byte v[8];
  2210.                         int j;
  2211.                         sptr -= 2;
  2212.                         png_memcpy(v, sptr, 2);
  2213.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2214.                         {
  2215.                            dp -= 2;
  2216.                            png_memcpy(dp, v, 2);
  2217.                         }
  2218.                      }
  2219.                   }
  2220.                   else if (width)  // pass == 4 or 5
  2221.                   {
  2222.                      int width_mmx = ((width >> 1) << 1) ;
  2223.                      width -= width_mmx;        // 0,1 pixels => 0,2 bytes
  2224.                      if (width_mmx)
  2225.                      {
  2226.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2227.                         int dummy_value_S;
  2228.                         int dummy_value_D;
  2229.  
  2230.                         __asm__ __volatile__ (
  2231.                            "subl $2, %%esi          \n\t"
  2232.                            "subl $6, %%edi          \n\t"
  2233.  
  2234.                         ".loop2_pass4:              \n\t"
  2235.                            "movd (%%esi), %%mm0     \n\t" // x x x x 3 2 1 0
  2236.                            "punpcklwd %%mm0, %%mm0  \n\t" // 3 2 3 2 1 0 1 0
  2237.                            "subl $4, %%esi          \n\t"
  2238.                            "movq %%mm0, (%%edi)     \n\t"
  2239.                            "subl $8, %%edi          \n\t"
  2240.                            "subl $2, %%ecx          \n\t"
  2241.                            "jnz .loop2_pass4        \n\t"
  2242.                            "EMMS                    \n\t" // DONE
  2243.  
  2244.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2245.                              "=S" (dummy_value_S),
  2246.                              "=D" (dummy_value_D)
  2247.  
  2248.                            : "1" (sptr),      // esi      // input regs
  2249.                              "2" (dp),        // edi
  2250.                              "0" (width_mmx)  // ecx
  2251.  
  2252. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2253.                            : "%mm0"                       // clobber list
  2254. #endif
  2255.                         );
  2256.                      }
  2257.  
  2258.                      sptr -= (width_mmx*2 - 2); // sign fixed
  2259.                      dp -= (width_mmx*4 - 2);   // sign fixed
  2260.                      for (i = width; i; i--)
  2261.                      {
  2262.                         png_byte v[8];
  2263.                         int j;
  2264.                         sptr -= 2;
  2265.                         png_memcpy(v, sptr, 2);
  2266.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2267.                         {
  2268.                            dp -= 2;
  2269.                            png_memcpy(dp, v, 2);
  2270.                         }
  2271.                      }
  2272.                   }
  2273.                } /* end of pixel_bytes == 2 */
  2274.  
  2275.                //--------------------------------------------------------------
  2276.                else if (pixel_bytes == 4)
  2277.                {
  2278.                   if (((pass == 0) || (pass == 1)) && width)
  2279.                   {
  2280.                      int width_mmx = ((width >> 1) << 1);
  2281.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2282.                      if (width_mmx)
  2283.                      {
  2284.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2285.                         int dummy_value_S;
  2286.                         int dummy_value_D;
  2287.  
  2288.                         __asm__ __volatile__ (
  2289.                            "subl $4, %%esi          \n\t"
  2290.                            "subl $60, %%edi         \n\t"
  2291.  
  2292.                         ".loop4_pass0:              \n\t"
  2293.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2294.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2295.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2296.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2297.                            "movq %%mm0, (%%edi)     \n\t"
  2298.                            "movq %%mm0, 8(%%edi)    \n\t"
  2299.                            "movq %%mm0, 16(%%edi)   \n\t"
  2300.                            "movq %%mm0, 24(%%edi)   \n\t"
  2301.                            "movq %%mm1, 32(%%edi)   \n\t"
  2302.                            "movq %%mm1, 40(%%edi)   \n\t"
  2303.                            "movq %%mm1, 48(%%edi)   \n\t"
  2304.                            "subl $8, %%esi          \n\t"
  2305.                            "movq %%mm1, 56(%%edi)   \n\t"
  2306.                            "subl $64, %%edi         \n\t"
  2307.                            "subl $2, %%ecx          \n\t"
  2308.                            "jnz .loop4_pass0        \n\t"
  2309.                            "EMMS                    \n\t" // DONE
  2310.  
  2311.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2312.                              "=S" (dummy_value_S),
  2313.                              "=D" (dummy_value_D)
  2314.  
  2315.                            : "1" (sptr),      // esi      // input regs
  2316.                              "2" (dp),        // edi
  2317.                              "0" (width_mmx)  // ecx
  2318.  
  2319. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2320.                            : "%mm0", "%mm1"               // clobber list
  2321. #endif
  2322.                         );
  2323.                      }
  2324.  
  2325.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2326.                      dp -= (width_mmx*32 - 4);  // sign fixed
  2327.                      for (i = width; i; i--)
  2328.                      {
  2329.                         png_byte v[8];
  2330.                         int j;
  2331.                         sptr -= 4;
  2332.                         png_memcpy(v, sptr, 4);
  2333.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2334.                         {
  2335.                            dp -= 4;
  2336.                            png_memcpy(dp, v, 4);
  2337.                         }
  2338.                      }
  2339.                   }
  2340.                   else if (((pass == 2) || (pass == 3)) && width)
  2341.                   {
  2342.                      int width_mmx = ((width >> 1) << 1);
  2343.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2344.                      if (width_mmx)
  2345.                      {
  2346.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2347.                         int dummy_value_S;
  2348.                         int dummy_value_D;
  2349.  
  2350.                         __asm__ __volatile__ (
  2351.                            "subl $4, %%esi          \n\t"
  2352.                            "subl $28, %%edi         \n\t"
  2353.  
  2354.                         ".loop4_pass2:              \n\t"
  2355.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2356.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2357.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2358.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2359.                            "movq %%mm0, (%%edi)     \n\t"
  2360.                            "movq %%mm0, 8(%%edi)    \n\t"
  2361.                            "movq %%mm1, 16(%%edi)   \n\t"
  2362.                            "movq %%mm1, 24(%%edi)   \n\t"
  2363.                            "subl $8, %%esi          \n\t"
  2364.                            "subl $32, %%edi         \n\t"
  2365.                            "subl $2, %%ecx          \n\t"
  2366.                            "jnz .loop4_pass2        \n\t"
  2367.                            "EMMS                    \n\t" // DONE
  2368.  
  2369.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2370.                              "=S" (dummy_value_S),
  2371.                              "=D" (dummy_value_D)
  2372.  
  2373.                            : "1" (sptr),      // esi      // input regs
  2374.                              "2" (dp),        // edi
  2375.                              "0" (width_mmx)  // ecx
  2376.  
  2377. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2378.                            : "%mm0", "%mm1"               // clobber list
  2379. #endif
  2380.                         );
  2381.                      }
  2382.  
  2383.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2384.                      dp -= (width_mmx*16 - 4);  // sign fixed
  2385.                      for (i = width; i; i--)
  2386.                      {
  2387.                         png_byte v[8];
  2388.                         int j;
  2389.                         sptr -= 4;
  2390.                         png_memcpy(v, sptr, 4);
  2391.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2392.                         {
  2393.                            dp -= 4;
  2394.                            png_memcpy(dp, v, 4);
  2395.                         }
  2396.                      }
  2397.                   }
  2398.                   else if (width)  // pass == 4 or 5
  2399.                   {
  2400.                      int width_mmx = ((width >> 1) << 1) ;
  2401.                      width -= width_mmx;        // 0,1 pixels => 0,4 bytes
  2402.                      if (width_mmx)
  2403.                      {
  2404.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2405.                         int dummy_value_S;
  2406.                         int dummy_value_D;
  2407.  
  2408.                         __asm__ __volatile__ (
  2409.                            "subl $4, %%esi          \n\t"
  2410.                            "subl $12, %%edi         \n\t"
  2411.  
  2412.                         ".loop4_pass4:              \n\t"
  2413.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2414.                            "movq %%mm0, %%mm1       \n\t" // 7 6 5 4 3 2 1 0
  2415.                            "punpckldq %%mm0, %%mm0  \n\t" // 3 2 1 0 3 2 1 0
  2416.                            "punpckhdq %%mm1, %%mm1  \n\t" // 7 6 5 4 7 6 5 4
  2417.                            "movq %%mm0, (%%edi)     \n\t"
  2418.                            "subl $8, %%esi          \n\t"
  2419.                            "movq %%mm1, 8(%%edi)    \n\t"
  2420.                            "subl $16, %%edi         \n\t"
  2421.                            "subl $2, %%ecx          \n\t"
  2422.                            "jnz .loop4_pass4        \n\t"
  2423.                            "EMMS                    \n\t" // DONE
  2424.  
  2425.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2426.                              "=S" (dummy_value_S),
  2427.                              "=D" (dummy_value_D)
  2428.  
  2429.                            : "1" (sptr),      // esi      // input regs
  2430.                              "2" (dp),        // edi
  2431.                              "0" (width_mmx)  // ecx
  2432.  
  2433. #if 0  /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2434.                            : "%mm0", "%mm1"               // clobber list
  2435. #endif
  2436.                         );
  2437.                      }
  2438.  
  2439.                      sptr -= (width_mmx*4 - 4); // sign fixed
  2440.                      dp -= (width_mmx*8 - 4);   // sign fixed
  2441.                      for (i = width; i; i--)
  2442.                      {
  2443.                         png_byte v[8];
  2444.                         int j;
  2445.                         sptr -= 4;
  2446.                         png_memcpy(v, sptr, 4);
  2447.                         for (j = 0; j < png_pass_inc[pass]; j++)
  2448.                         {
  2449.                            dp -= 4;
  2450.                            png_memcpy(dp, v, 4);
  2451.                         }
  2452.                      }
  2453.                   }
  2454.                } /* end of pixel_bytes == 4 */
  2455.  
  2456.                //--------------------------------------------------------------
  2457.                else if (pixel_bytes == 8)
  2458.                {
  2459. // GRR TEST:  should work, but needs testing (special 64-bit version of rpng2?)
  2460.                   // GRR NOTE:  no need to combine passes here!
  2461.                   if (((pass == 0) || (pass == 1)) && width)
  2462.                   {
  2463.                      int dummy_value_c;  // fix 'forbidden register spilled'
  2464.                      int dummy_value_S;
  2465.                      int dummy_value_D;
  2466.  
  2467.                      // source is 8-byte RRGGBBAA
  2468.                      // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ...
  2469.                      __asm__ __volatile__ (
  2470.                         "subl $56, %%edi         \n\t" // start of last block
  2471.  
  2472.                      ".loop8_pass0:              \n\t"
  2473.                         "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2474.                         "movq %%mm0, (%%edi)     \n\t"
  2475.                         "movq %%mm0, 8(%%edi)    \n\t"
  2476.                         "movq %%mm0, 16(%%edi)   \n\t"
  2477.                         "movq %%mm0, 24(%%edi)   \n\t"
  2478.                         "movq %%mm0, 32(%%edi)   \n\t"
  2479.                         "movq %%mm0, 40(%%edi)   \n\t"
  2480.                         "movq %%mm0, 48(%%edi)   \n\t"
  2481.                         "subl $8, %%esi          \n\t"
  2482.                         "movq %%mm0, 56(%%edi)   \n\t"
  2483.                         "subl $64, %%edi         \n\t"
  2484.                         "decl %%ecx              \n\t"
  2485.                         "jnz .loop8_pass0        \n\t"
  2486.                         "EMMS                    \n\t" // DONE
  2487.  
  2488.                         : "=c" (dummy_value_c),        // output regs (dummy)
  2489.                           "=S" (dummy_value_S),
  2490.                           "=D" (dummy_value_D)
  2491.  
  2492.                         : "1" (sptr),      // esi      // input regs
  2493.                           "2" (dp),        // edi
  2494.                           "0" (width)      // ecx
  2495.  
  2496. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2497.                         : "%mm0"                       // clobber list
  2498. #endif
  2499.                      );
  2500.                   }
  2501.                   else if (((pass == 2) || (pass == 3)) && width)
  2502.                   {
  2503.                      // source is 8-byte RRGGBBAA
  2504.                      // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA
  2505.                      // (recall that expansion is _in place_:  sptr and dp
  2506.                      //  both point at locations within same row buffer)
  2507.                      {
  2508.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2509.                         int dummy_value_S;
  2510.                         int dummy_value_D;
  2511.  
  2512.                         __asm__ __volatile__ (
  2513.                            "subl $24, %%edi         \n\t" // start of last block
  2514.  
  2515.                         ".loop8_pass2:              \n\t"
  2516.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2517.                            "movq %%mm0, (%%edi)     \n\t"
  2518.                            "movq %%mm0, 8(%%edi)    \n\t"
  2519.                            "movq %%mm0, 16(%%edi)   \n\t"
  2520.                            "subl $8, %%esi          \n\t"
  2521.                            "movq %%mm0, 24(%%edi)   \n\t"
  2522.                            "subl $32, %%edi         \n\t"
  2523.                            "decl %%ecx              \n\t"
  2524.                            "jnz .loop8_pass2        \n\t"
  2525.                            "EMMS                    \n\t" // DONE
  2526.  
  2527.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2528.                              "=S" (dummy_value_S),
  2529.                              "=D" (dummy_value_D)
  2530.  
  2531.                            : "1" (sptr),      // esi      // input regs
  2532.                              "2" (dp),        // edi
  2533.                              "0" (width)      // ecx
  2534.  
  2535. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2536.                            : "%mm0"                       // clobber list
  2537. #endif
  2538.                         );
  2539.                      }
  2540.                   }
  2541.                   else if (width)  // pass == 4 or 5
  2542.                   {
  2543.                      // source is 8-byte RRGGBBAA
  2544.                      // dest is 16-byte RRGGBBAA RRGGBBAA
  2545.                      {
  2546.                         int dummy_value_c;  // fix 'forbidden register spilled'
  2547.                         int dummy_value_S;
  2548.                         int dummy_value_D;
  2549.  
  2550.                         __asm__ __volatile__ (
  2551.                            "subl $8, %%edi          \n\t" // start of last block
  2552.  
  2553.                         ".loop8_pass4:              \n\t"
  2554.                            "movq (%%esi), %%mm0     \n\t" // 7 6 5 4 3 2 1 0
  2555.                            "movq %%mm0, (%%edi)     \n\t"
  2556.                            "subl $8, %%esi          \n\t"
  2557.                            "movq %%mm0, 8(%%edi)    \n\t"
  2558.                            "subl $16, %%edi         \n\t"
  2559.                            "decl %%ecx              \n\t"
  2560.                            "jnz .loop8_pass4        \n\t"
  2561.                            "EMMS                    \n\t" // DONE
  2562.  
  2563.                            : "=c" (dummy_value_c),        // output regs (dummy)
  2564.                              "=S" (dummy_value_S),
  2565.                              "=D" (dummy_value_D)
  2566.  
  2567.                            : "1" (sptr),      // esi      // input regs
  2568.                              "2" (dp),        // edi
  2569.                              "0" (width)      // ecx
  2570.  
  2571. #if 0  /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2572.                            : "%mm0"                       // clobber list
  2573. #endif
  2574.                         );
  2575.                      }
  2576.                   }
  2577.  
  2578.                } /* end of pixel_bytes == 8 */
  2579.  
  2580.                //--------------------------------------------------------------
  2581.                else if (pixel_bytes == 6)
  2582.                {
  2583.                   for (i = width; i; i--)
  2584.                   {
  2585.                      png_byte v[8];
  2586.                      int j;
  2587.                      png_memcpy(v, sptr, 6);
  2588.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2589.                      {
  2590.                         png_memcpy(dp, v, 6);
  2591.                         dp -= 6;
  2592.                      }
  2593.                      sptr -= 6;
  2594.                   }
  2595.                } /* end of pixel_bytes == 6 */
  2596.  
  2597.                //--------------------------------------------------------------
  2598.                else
  2599.                {
  2600.                   for (i = width; i; i--)
  2601.                   {
  2602.                      png_byte v[8];
  2603.                      int j;
  2604.                      png_memcpy(v, sptr, pixel_bytes);
  2605.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2606.                      {
  2607.                         png_memcpy(dp, v, pixel_bytes);
  2608.                         dp -= pixel_bytes;
  2609.                      }
  2610.                      sptr-= pixel_bytes;
  2611.                   }
  2612.                }
  2613.             } // end of _mmx_supported ========================================
  2614.  
  2615.             else /* MMX not supported:  use modified C code - takes advantage
  2616.                   *   of inlining of png_memcpy for a constant */
  2617.                  /* GRR 19991007:  does it?  or should pixel_bytes in each
  2618.                   *   block be replaced with immediate value (e.g., 1)? */
  2619.                  /* GRR 19991017:  replaced with constants in each case */
  2620. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  2621.             {
  2622.                if (pixel_bytes == 1)
  2623.                {
  2624.                   for (i = width; i; i--)
  2625.                   {
  2626.                      int j;
  2627.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2628.                      {
  2629.                         *dp-- = *sptr;
  2630.                      }
  2631.                      --sptr;
  2632.                   }
  2633.                }
  2634.                else if (pixel_bytes == 3)
  2635.                {
  2636.                   for (i = width; i; i--)
  2637.                   {
  2638.                      png_byte v[8];
  2639.                      int j;
  2640.                      png_memcpy(v, sptr, 3);
  2641.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2642.                      {
  2643.                         png_memcpy(dp, v, 3);
  2644.                         dp -= 3;
  2645.                      }
  2646.                      sptr -= 3;
  2647.                   }
  2648.                }
  2649.                else if (pixel_bytes == 2)
  2650.                {
  2651.                   for (i = width; i; i--)
  2652.                   {
  2653.                      png_byte v[8];
  2654.                      int j;
  2655.                      png_memcpy(v, sptr, 2);
  2656.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2657.                      {
  2658.                         png_memcpy(dp, v, 2);
  2659.                         dp -= 2;
  2660.                      }
  2661.                      sptr -= 2;
  2662.                   }
  2663.                }
  2664.                else if (pixel_bytes == 4)
  2665.                {
  2666.                   for (i = width; i; i--)
  2667.                   {
  2668.                      png_byte v[8];
  2669.                      int j;
  2670.                      png_memcpy(v, sptr, 4);
  2671.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2672.                      {
  2673. #ifdef PNG_DEBUG
  2674.                         if (dp < row || dp+3 > row+png_ptr->row_buf_size)
  2675.                         {
  2676.                            printf("dp out of bounds: row=%d, dp=%d, rp=%d\n",
  2677.                              row, dp, row+png_ptr->row_buf_size);
  2678.                            printf("row_buf=%d\n",png_ptr->row_buf_size);
  2679.                         }
  2680. #endif
  2681.                         png_memcpy(dp, v, 4);
  2682.                         dp -= 4;
  2683.                      }
  2684.                      sptr -= 4;
  2685.                   }
  2686.                }
  2687.                else if (pixel_bytes == 6)
  2688.                {
  2689.                   for (i = width; i; i--)
  2690.                   {
  2691.                      png_byte v[8];
  2692.                      int j;
  2693.                      png_memcpy(v, sptr, 6);
  2694.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2695.                      {
  2696.                         png_memcpy(dp, v, 6);
  2697.                         dp -= 6;
  2698.                      }
  2699.                      sptr -= 6;
  2700.                   }
  2701.                }
  2702.                else if (pixel_bytes == 8)
  2703.                {
  2704.                   for (i = width; i; i--)
  2705.                   {
  2706.                      png_byte v[8];
  2707.                      int j;
  2708.                      png_memcpy(v, sptr, 8);
  2709.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2710.                      {
  2711.                         png_memcpy(dp, v, 8);
  2712.                         dp -= 8;
  2713.                      }
  2714.                      sptr -= 8;
  2715.                   }
  2716.                }
  2717.                else     /* GRR:  should never be reached */
  2718.                {
  2719.                   for (i = width; i; i--)
  2720.                   {
  2721.                      png_byte v[8];
  2722.                      int j;
  2723.                      png_memcpy(v, sptr, pixel_bytes);
  2724.                      for (j = 0; j < png_pass_inc[pass]; j++)
  2725.                      {
  2726.                         png_memcpy(dp, v, pixel_bytes);
  2727.                         dp -= pixel_bytes;
  2728.                      }
  2729.                      sptr -= pixel_bytes;
  2730.                   }
  2731.                }
  2732.  
  2733.             } /* end if (MMX not supported) */
  2734.             break;
  2735.          }
  2736.       } /* end switch (row_info->pixel_depth) */
  2737.  
  2738.       row_info->width = final_width;
  2739.  
  2740.       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
  2741.    }
  2742.  
  2743. } /* end png_do_read_interlace() */
  2744.  
  2745. #endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */
  2746. #endif /* PNG_READ_INTERLACING_SUPPORTED */
  2747.  
  2748.  
  2749.  
  2750. #if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW)
  2751. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  2752.  
  2753. // These variables are utilized in the functions below.  They are declared
  2754. // globally here to ensure alignment on 8-byte boundaries.
  2755.  
  2756. union uAll {
  2757.    long long use;
  2758.    double  align;
  2759. } _LBCarryMask = {0x0101010101010101LL},
  2760.   _HBClearMask = {0x7f7f7f7f7f7f7f7fLL},
  2761.   _ActiveMask, _ActiveMask2, _ActiveMaskEnd, _ShiftBpp, _ShiftRem;
  2762.  
  2763. #ifdef PNG_THREAD_UNSAFE_OK
  2764. //===========================================================================//
  2765. //                                                                           //
  2766. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G           //
  2767. //                                                                           //
  2768. //===========================================================================//
  2769.  
  2770. // Optimized code for PNG Average filter decoder
  2771.  
  2772. static void /* PRIVATE */
  2773. png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row,
  2774.                             png_bytep prev_row)
  2775. {
  2776.    int bpp;
  2777.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  2778.    int dummy_value_S;
  2779.    int dummy_value_D;
  2780.  
  2781.    bpp = (row_info->pixel_depth + 7) >> 3;  // get # bytes per pixel
  2782.    _FullLength  = row_info->rowbytes;       // # of bytes to filter
  2783.  
  2784.    __asm__ __volatile__ (
  2785.       // initialize address pointers and offset
  2786. #ifdef __PIC__
  2787.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  2788. #endif
  2789. //pre "movl row, %%edi             \n\t" // edi:  Avg(x)
  2790.       "xorl %%ebx, %%ebx           \n\t" // ebx:  x
  2791.       "movl %%edi, %%edx           \n\t"
  2792. //pre "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  2793. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  2794.       "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  2795.  
  2796.       "xorl %%eax,%%eax            \n\t"
  2797.  
  2798.       // Compute the Raw value for the first bpp bytes
  2799.       //    Raw(x) = Avg(x) + (Prior(x)/2)
  2800.    "avg_rlp:                       \n\t"
  2801.       "movb (%%esi,%%ebx,),%%al    \n\t" // load al with Prior(x)
  2802.       "incl %%ebx                  \n\t"
  2803.       "shrb %%al                   \n\t" // divide by 2
  2804.       "addb -1(%%edi,%%ebx,),%%al  \n\t" // add Avg(x); -1 to offset inc ebx
  2805. //pre "cmpl bpp, %%ebx             \n\t" // (bpp is preloaded into ecx)
  2806.       "cmpl %%ecx, %%ebx           \n\t"
  2807.       "movb %%al,-1(%%edi,%%ebx,)  \n\t" // write Raw(x); -1 to offset inc ebx
  2808.       "jb avg_rlp                  \n\t" // mov does not affect flags
  2809.  
  2810.       // get # of bytes to alignment
  2811.       "movl %%edi, _dif            \n\t" // take start of row
  2812.       "addl %%ebx, _dif            \n\t" // add bpp
  2813.       "addl $0xf, _dif             \n\t" // add 7+8 to incr past alignment bdry
  2814.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  2815.       "subl %%edi, _dif            \n\t" // subtract from start => value ebx at
  2816.       "jz avg_go                   \n\t" //  alignment
  2817.  
  2818.       // fix alignment
  2819.       // Compute the Raw value for the bytes up to the alignment boundary
  2820.       //    Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  2821.       "xorl %%ecx, %%ecx           \n\t"
  2822.  
  2823.    "avg_lp1:                       \n\t"
  2824.       "xorl %%eax, %%eax           \n\t"
  2825.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  2826.       "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  2827.       "addw %%cx, %%ax             \n\t"
  2828.       "incl %%ebx                  \n\t"
  2829.       "shrw %%ax                   \n\t" // divide by 2
  2830.       "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
  2831.       "cmpl _dif, %%ebx            \n\t" // check if at alignment boundary
  2832.       "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx
  2833.       "jb avg_lp1                  \n\t" // repeat until at alignment boundary
  2834.  
  2835.    "avg_go:                        \n\t"
  2836.       "movl _FullLength, %%eax     \n\t"
  2837.       "movl %%eax, %%ecx           \n\t"
  2838.       "subl %%ebx, %%eax           \n\t" // subtract alignment fix
  2839.       "andl $0x00000007, %%eax     \n\t" // calc bytes over mult of 8
  2840.       "subl %%eax, %%ecx           \n\t" // drop over bytes from original length
  2841.       "movl %%ecx, _MMXLength      \n\t"
  2842. #ifdef __PIC__
  2843.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  2844. #endif
  2845.  
  2846.       : "=c" (dummy_value_c),            // output regs (dummy)
  2847.         "=S" (dummy_value_S),
  2848.         "=D" (dummy_value_D)
  2849.  
  2850.       : "0" (bpp),       // ecx          // input regs
  2851.         "1" (prev_row),  // esi
  2852.         "2" (row)        // edi
  2853.  
  2854.       : "%eax", "%edx"                   // clobber list
  2855. #ifndef __PIC__
  2856.       , "%ebx"
  2857. #endif
  2858.       // GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength)
  2859.       // (seems to work fine without...)
  2860.    );
  2861.  
  2862.    // now do the math for the rest of the row
  2863.    switch (bpp)
  2864.    {
  2865.       case 3:
  2866.       {
  2867.          _ActiveMask.use  = 0x0000000000ffffffLL;
  2868.          _ShiftBpp.use = 24;    // == 3 * 8
  2869.          _ShiftRem.use = 40;    // == 64 - 24
  2870.  
  2871.          __asm__ __volatile__ (
  2872.             // re-init address pointers and offset
  2873.             "movq _ActiveMask, %%mm7      \n\t"
  2874.             "movl _dif, %%ecx             \n\t" // ecx:  x = offset to
  2875.             "movq _LBCarryMask, %%mm5     \n\t" //  alignment boundary
  2876. // preload  "movl row, %%edi              \n\t" // edi:  Avg(x)
  2877.             "movq _HBClearMask, %%mm4     \n\t"
  2878. // preload  "movl prev_row, %%esi         \n\t" // esi:  Prior(x)
  2879.  
  2880.             // prime the pump:  load the first Raw(x-bpp) data set
  2881.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  2882.                                                 // (correct pos. in loop below)
  2883.          "avg_3lp:                        \n\t"
  2884.             "movq (%%edi,%%ecx,), %%mm0   \n\t" // load mm0 with Avg(x)
  2885.             "movq %%mm5, %%mm3            \n\t"
  2886.             "psrlq _ShiftRem, %%mm2       \n\t" // correct position Raw(x-bpp)
  2887.                                                 // data
  2888.             "movq (%%esi,%%ecx,), %%mm1   \n\t" // load mm1 with Prior(x)
  2889.             "movq %%mm7, %%mm6            \n\t"
  2890.             "pand %%mm1, %%mm3            \n\t" // get lsb for each prev_row byte
  2891.             "psrlq $1, %%mm1              \n\t" // divide prev_row bytes by 2
  2892.             "pand  %%mm4, %%mm1           \n\t" // clear invalid bit 7 of each
  2893.                                                 // byte
  2894.             "paddb %%mm1, %%mm0           \n\t" // add (Prev_row/2) to Avg for
  2895.                                                 // each byte
  2896.             // add 1st active group (Raw(x-bpp)/2) to average with LBCarry
  2897.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting
  2898.                                                 // LBCarrys
  2899.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte
  2900.                                                 // where both
  2901.                                // lsb's were == 1 (only valid for active group)
  2902.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2903.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each
  2904.                                                 // byte
  2905.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  2906.                                                 // for each byte
  2907.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 1
  2908.                                                 // bytes to add to Avg
  2909.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to
  2910.                                                 // Avg for each Active
  2911.                                //  byte
  2912.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  2913.             "psllq _ShiftBpp, %%mm6       \n\t" // shift the mm6 mask to cover
  2914.                                                 // bytes 3-5
  2915.             "movq %%mm0, %%mm2            \n\t" // mov updated Raws to mm2
  2916.             "psllq _ShiftBpp, %%mm2       \n\t" // shift data to pos. correctly
  2917.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting
  2918.                                                 // LBCarrys
  2919.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte
  2920.                                                 // where both
  2921.                                // lsb's were == 1 (only valid for active group)
  2922.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2923.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each
  2924.                                                 // byte
  2925.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  2926.                                                 // for each byte
  2927.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 2
  2928.                                                 // bytes to add to Avg
  2929.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to
  2930.                                                 // Avg for each Active
  2931.                                //  byte
  2932.  
  2933.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  2934.             "psllq _ShiftBpp, %%mm6       \n\t" // shift mm6 mask to cover last
  2935.                                                 // two
  2936.                                  // bytes
  2937.             "movq %%mm0, %%mm2            \n\t" // mov updated Raws to mm2
  2938.             "psllq _ShiftBpp, %%mm2       \n\t" // shift data to pos. correctly
  2939.                               // Data only needs to be shifted once here to
  2940.                               // get the correct x-bpp offset.
  2941.             "movq %%mm3, %%mm1            \n\t" // now use mm1 for getting
  2942.                                                 // LBCarrys
  2943.             "pand %%mm2, %%mm1            \n\t" // get LBCarrys for each byte
  2944.                                                 // where both
  2945.                               // lsb's were == 1 (only valid for active group)
  2946.             "psrlq $1, %%mm2              \n\t" // divide raw bytes by 2
  2947.             "pand  %%mm4, %%mm2           \n\t" // clear invalid bit 7 of each
  2948.                                                 // byte
  2949.             "paddb %%mm1, %%mm2           \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  2950.                                                 // for each byte
  2951.             "pand %%mm6, %%mm2            \n\t" // leave only Active Group 2
  2952.                                                 // bytes to add to Avg
  2953.             "addl $8, %%ecx               \n\t"
  2954.             "paddb %%mm2, %%mm0           \n\t" // add (Raw/2) + LBCarrys to
  2955.                                                 // Avg for each Active
  2956.                                                 // byte
  2957.             // now ready to write back to memory
  2958.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  2959.             // move updated Raw(x) to use as Raw(x-bpp) for next loop
  2960.             "cmpl _MMXLength, %%ecx       \n\t"
  2961.             "movq %%mm0, %%mm2            \n\t" // mov updated Raw(x) to mm2
  2962.             "jb avg_3lp                   \n\t"
  2963.  
  2964.             : "=S" (dummy_value_S),             // output regs (dummy)
  2965.               "=D" (dummy_value_D)
  2966.  
  2967.             : "0" (prev_row),  // esi           // input regs
  2968.               "1" (row)        // edi
  2969.  
  2970.             : "%ecx"                            // clobber list
  2971. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  2972.             , "%mm0", "%mm1", "%mm2", "%mm3"
  2973.             , "%mm4", "%mm5", "%mm6", "%mm7"
  2974. #endif
  2975.          );
  2976.       }
  2977.       break;  // end 3 bpp
  2978.  
  2979.       case 6:
  2980.       case 4:
  2981.       //case 7:   // who wrote this?  PNG doesn't support 5 or 7 bytes/pixel
  2982.       //case 5:   // GRR BOGUS
  2983.       {
  2984.          _ActiveMask.use  = 0xffffffffffffffffLL; // use shift below to clear
  2985.                                                   // appropriate inactive bytes
  2986.          _ShiftBpp.use = bpp << 3;
  2987.          _ShiftRem.use = 64 - _ShiftBpp.use;
  2988.  
  2989.          __asm__ __volatile__ (
  2990.             "movq _HBClearMask, %%mm4    \n\t"
  2991.  
  2992.             // re-init address pointers and offset
  2993.             "movl _dif, %%ecx            \n\t" // ecx:  x = offset to
  2994.                                                // alignment boundary
  2995.  
  2996.             // load _ActiveMask and clear all bytes except for 1st active group
  2997.             "movq _ActiveMask, %%mm7     \n\t"
  2998. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  2999.             "psrlq _ShiftRem, %%mm7      \n\t"
  3000. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3001.             "movq %%mm7, %%mm6           \n\t"
  3002.             "movq _LBCarryMask, %%mm5    \n\t"
  3003.             "psllq _ShiftBpp, %%mm6      \n\t" // create mask for 2nd active
  3004.                                                // group
  3005.  
  3006.             // prime the pump:  load the first Raw(x-bpp) data set
  3007.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  3008.                                           // (we correct pos. in loop below)
  3009.          "avg_4lp:                       \n\t"
  3010.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  3011.             "psrlq _ShiftRem, %%mm2      \n\t" // shift data to pos. correctly
  3012.             "movq (%%esi,%%ecx,), %%mm1  \n\t"
  3013.             // add (Prev_row/2) to average
  3014.             "movq %%mm5, %%mm3           \n\t"
  3015.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3016.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3017.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each
  3018.                                                // byte
  3019.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for
  3020.                                                // each byte
  3021.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  3022.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3023.                                                // LBCarrys
  3024.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3025.                                                // where both
  3026.                               // lsb's were == 1 (only valid for active group)
  3027.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3028.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3029.                                                // byte
  3030.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3031.                                                // for each byte
  3032.             "pand %%mm7, %%mm2           \n\t" // leave only Active Group 1
  3033.                                                // bytes to add to Avg
  3034.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg
  3035.                                                // for each Active
  3036.                               // byte
  3037.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  3038.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3039.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3040.             "addl $8, %%ecx              \n\t"
  3041.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3042.                                                // LBCarrys
  3043.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3044.                                                // where both
  3045.                               // lsb's were == 1 (only valid for active group)
  3046.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3047.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3048.                                                // byte
  3049.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3050.                                                // for each byte
  3051.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2
  3052.                                                // bytes to add to Avg
  3053.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to
  3054.                                                // Avg for each Active
  3055.                               // byte
  3056.             "cmpl _MMXLength, %%ecx      \n\t"
  3057.             // now ready to write back to memory
  3058.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  3059.             // prep Raw(x-bpp) for next loop
  3060.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3061.             "jb avg_4lp                  \n\t"
  3062.  
  3063.             : "=S" (dummy_value_S),            // output regs (dummy)
  3064.               "=D" (dummy_value_D)
  3065.  
  3066.             : "0" (prev_row),  // esi          // input regs
  3067.               "1" (row)        // edi
  3068.  
  3069.             : "%ecx"                           // clobber list
  3070. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3071.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3072.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3073. #endif
  3074.          );
  3075.       }
  3076.       break;  // end 4,6 bpp
  3077.  
  3078.       case 2:
  3079.       {
  3080.          _ActiveMask.use  = 0x000000000000ffffLL;
  3081.          _ShiftBpp.use = 16;   // == 2 * 8
  3082.          _ShiftRem.use = 48;   // == 64 - 16
  3083.  
  3084.          __asm__ __volatile__ (
  3085.             // load _ActiveMask
  3086.             "movq _ActiveMask, %%mm7     \n\t"
  3087.             // re-init address pointers and offset
  3088.             "movl _dif, %%ecx            \n\t" // ecx:  x = offset to alignment
  3089.                                                // boundary
  3090.             "movq _LBCarryMask, %%mm5    \n\t"
  3091. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  3092.             "movq _HBClearMask, %%mm4    \n\t"
  3093. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3094.  
  3095.             // prime the pump:  load the first Raw(x-bpp) data set
  3096.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  3097.                               // (we correct pos. in loop below)
  3098.          "avg_2lp:                       \n\t"
  3099.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  3100.             "psrlq _ShiftRem, %%mm2      \n\t" // shift data to pos. correctly
  3101.             "movq (%%esi,%%ecx,), %%mm1  \n\t" //  (GRR BUGFIX:  was psllq)
  3102.             // add (Prev_row/2) to average
  3103.             "movq %%mm5, %%mm3           \n\t"
  3104.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3105.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3106.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each
  3107.                                                // byte
  3108.             "movq %%mm7, %%mm6           \n\t"
  3109.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for
  3110.                                                // each byte
  3111.  
  3112.             // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
  3113.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3114.                                                // LBCarrys
  3115.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3116.                                                // where both
  3117.                                                // lsb's were == 1 (only valid
  3118.                                                // for active group)
  3119.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3120.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3121.                                                // byte
  3122.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3123.                                                // for each byte
  3124.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 1
  3125.                                                // bytes to add to Avg
  3126.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to Avg
  3127.                                                // for each Active byte
  3128.  
  3129.             // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
  3130.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover
  3131.                                                // bytes 2 & 3
  3132.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3133.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3134.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3135.                                                // LBCarrys
  3136.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3137.                                                // where both
  3138.                                                // lsb's were == 1 (only valid
  3139.                                                // for active group)
  3140.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3141.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3142.                                                // byte
  3143.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3144.                                                // for each byte
  3145.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2
  3146.                                                // bytes to add to Avg
  3147.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to
  3148.                                                // Avg for each Active byte
  3149.  
  3150.             // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
  3151.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover
  3152.                                                // bytes 4 & 5
  3153.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3154.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3155.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3156.                                                // LBCarrys
  3157.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3158.                                                // where both lsb's were == 1
  3159.                                                // (only valid for active group)
  3160.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3161.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3162.                                                // byte
  3163.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3164.                                                // for each byte
  3165.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2
  3166.                                                // bytes to add to Avg
  3167.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to
  3168.                                                // Avg for each Active byte
  3169.  
  3170.             // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry
  3171.             "psllq _ShiftBpp, %%mm6      \n\t" // shift the mm6 mask to cover
  3172.                                                // bytes 6 & 7
  3173.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3174.             "psllq _ShiftBpp, %%mm2      \n\t" // shift data to pos. correctly
  3175.             "addl $8, %%ecx              \n\t"
  3176.             "movq %%mm3, %%mm1           \n\t" // now use mm1 for getting
  3177.                                                // LBCarrys
  3178.             "pand %%mm2, %%mm1           \n\t" // get LBCarrys for each byte
  3179.                                                // where both
  3180.                                                // lsb's were == 1 (only valid
  3181.                                                // for active group)
  3182.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3183.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3184.                                                // byte
  3185.             "paddb %%mm1, %%mm2          \n\t" // add LBCarrys to (Raw(x-bpp)/2)
  3186.                                                // for each byte
  3187.             "pand %%mm6, %%mm2           \n\t" // leave only Active Group 2
  3188.                                                // bytes to add to Avg
  3189.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) + LBCarrys to
  3190.                                                // Avg for each Active byte
  3191.  
  3192.             "cmpl _MMXLength, %%ecx      \n\t"
  3193.             // now ready to write back to memory
  3194.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  3195.             // prep Raw(x-bpp) for next loop
  3196.             "movq %%mm0, %%mm2           \n\t" // mov updated Raws to mm2
  3197.             "jb avg_2lp                  \n\t"
  3198.  
  3199.             : "=S" (dummy_value_S),            // output regs (dummy)
  3200.               "=D" (dummy_value_D)
  3201.  
  3202.             : "0" (prev_row),  // esi          // input regs
  3203.               "1" (row)        // edi
  3204.  
  3205.             : "%ecx"                           // clobber list
  3206. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3207.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3208.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3209. #endif
  3210.          );
  3211.       }
  3212.       break;  // end 2 bpp
  3213.  
  3214.       case 1:
  3215.       {
  3216.          __asm__ __volatile__ (
  3217.             // re-init address pointers and offset
  3218. #ifdef __PIC__
  3219.             "pushl %%ebx                 \n\t" // save Global Offset Table index
  3220. #endif
  3221.             "movl _dif, %%ebx            \n\t" // ebx:  x = offset to alignment
  3222.                                                // boundary
  3223. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  3224.             "cmpl _FullLength, %%ebx     \n\t" // test if offset at end of array
  3225.             "jnb avg_1end                \n\t"
  3226.             // do Paeth decode for remaining bytes
  3227. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3228.             "movl %%edi, %%edx           \n\t"
  3229. // preload  "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  3230.             "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  3231.             "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx
  3232.                                                //  in loop below
  3233.          "avg_1lp:                       \n\t"
  3234.             // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  3235.             "xorl %%eax, %%eax           \n\t"
  3236.             "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  3237.             "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  3238.             "addw %%cx, %%ax             \n\t"
  3239.             "incl %%ebx                  \n\t"
  3240.             "shrw %%ax                   \n\t" // divide by 2
  3241.             "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset
  3242.                                                // inc ebx
  3243.             "cmpl _FullLength, %%ebx     \n\t" // check if at end of array
  3244.             "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x);
  3245.                          // mov does not affect flags; -1 to offset inc ebx
  3246.             "jb avg_1lp                  \n\t"
  3247.  
  3248.          "avg_1end:                      \n\t"
  3249. #ifdef __PIC__
  3250.             "popl %%ebx                  \n\t" // Global Offset Table index
  3251. #endif
  3252.  
  3253.             : "=c" (dummy_value_c),            // output regs (dummy)
  3254.               "=S" (dummy_value_S),
  3255.               "=D" (dummy_value_D)
  3256.  
  3257.             : "0" (bpp),       // ecx          // input regs
  3258.               "1" (prev_row),  // esi
  3259.               "2" (row)        // edi
  3260.  
  3261.             : "%eax", "%edx"                   // clobber list
  3262. #ifndef __PIC__
  3263.             , "%ebx"
  3264. #endif
  3265.          );
  3266.       }
  3267.       return;  // end 1 bpp
  3268.  
  3269.       case 8:
  3270.       {
  3271.          __asm__ __volatile__ (
  3272.             // re-init address pointers and offset
  3273.             "movl _dif, %%ecx            \n\t" // ecx:  x == offset to alignment
  3274.             "movq _LBCarryMask, %%mm5    \n\t" //            boundary
  3275. // preload  "movl row, %%edi             \n\t" // edi:  Avg(x)
  3276.             "movq _HBClearMask, %%mm4    \n\t"
  3277. // preload  "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3278.  
  3279.             // prime the pump:  load the first Raw(x-bpp) data set
  3280.             "movq -8(%%edi,%%ecx,), %%mm2 \n\t" // load previous aligned 8 bytes
  3281.                                       // (NO NEED to correct pos. in loop below)
  3282.  
  3283.          "avg_8lp:                       \n\t"
  3284.             "movq (%%edi,%%ecx,), %%mm0  \n\t"
  3285.             "movq %%mm5, %%mm3           \n\t"
  3286.             "movq (%%esi,%%ecx,), %%mm1  \n\t"
  3287.             "addl $8, %%ecx              \n\t"
  3288.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3289.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3290.             "pand %%mm2, %%mm3           \n\t" // get LBCarrys for each byte
  3291.                                                //  where both lsb's were == 1
  3292.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3293.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7, each byte
  3294.             "paddb %%mm3, %%mm0          \n\t" // add LBCarrys to Avg, each byte
  3295.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7, each byte
  3296.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg, each
  3297.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) to Avg for each
  3298.             "cmpl _MMXLength, %%ecx      \n\t"
  3299.             "movq %%mm0, -8(%%edi,%%ecx,) \n\t"
  3300.             "movq %%mm0, %%mm2           \n\t" // reuse as Raw(x-bpp)
  3301.             "jb avg_8lp                  \n\t"
  3302.  
  3303.             : "=S" (dummy_value_S),            // output regs (dummy)
  3304.               "=D" (dummy_value_D)
  3305.  
  3306.             : "0" (prev_row),  // esi          // input regs
  3307.               "1" (row)        // edi
  3308.  
  3309.             : "%ecx"                           // clobber list
  3310. #if 0  /* %mm0, ..., %mm5 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3311.             , "%mm0", "%mm1", "%mm2"
  3312.             , "%mm3", "%mm4", "%mm5"
  3313. #endif
  3314.          );
  3315.       }
  3316.       break;  // end 8 bpp
  3317.  
  3318.       default:                  // bpp greater than 8 (!= 1,2,3,4,[5],6,[7],8)
  3319.       {
  3320.  
  3321. #ifdef PNG_DEBUG
  3322.          // GRR:  PRINT ERROR HERE:  SHOULD NEVER BE REACHED
  3323.         png_debug(1,
  3324.         "Internal logic error in pnggccrd (png_read_filter_row_mmx_avg())\n");
  3325. #endif
  3326.  
  3327. #if 0
  3328.         __asm__ __volatile__ (
  3329.             "movq _LBCarryMask, %%mm5    \n\t"
  3330.             // re-init address pointers and offset
  3331.             "movl _dif, %%ebx            \n\t" // ebx:  x = offset to
  3332.                                                // alignment boundary
  3333.             "movl row, %%edi             \n\t" // edi:  Avg(x)
  3334.             "movq _HBClearMask, %%mm4    \n\t"
  3335.             "movl %%edi, %%edx           \n\t"
  3336.             "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3337.             "subl bpp, %%edx             \n\t" // edx:  Raw(x-bpp)
  3338.          "avg_Alp:                       \n\t"
  3339.             "movq (%%edi,%%ebx,), %%mm0  \n\t"
  3340.             "movq %%mm5, %%mm3           \n\t"
  3341.             "movq (%%esi,%%ebx,), %%mm1  \n\t"
  3342.             "pand %%mm1, %%mm3           \n\t" // get lsb for each prev_row byte
  3343.             "movq (%%edx,%%ebx,), %%mm2  \n\t"
  3344.             "psrlq $1, %%mm1             \n\t" // divide prev_row bytes by 2
  3345.             "pand %%mm2, %%mm3           \n\t" // get LBCarrys for each byte
  3346.                                                // where both lsb's were == 1
  3347.             "psrlq $1, %%mm2             \n\t" // divide raw bytes by 2
  3348.             "pand  %%mm4, %%mm1          \n\t" // clear invalid bit 7 of each
  3349.                                                // byte
  3350.             "paddb %%mm3, %%mm0          \n\t" // add LBCarrys to Avg for each
  3351.                                                // byte
  3352.             "pand  %%mm4, %%mm2          \n\t" // clear invalid bit 7 of each
  3353.                                                // byte
  3354.             "paddb %%mm1, %%mm0          \n\t" // add (Prev_row/2) to Avg for
  3355.                                                // each byte
  3356.             "addl $8, %%ebx              \n\t"
  3357.             "paddb %%mm2, %%mm0          \n\t" // add (Raw/2) to Avg for each
  3358.                                                // byte
  3359.             "cmpl _MMXLength, %%ebx      \n\t"
  3360.             "movq %%mm0, -8(%%edi,%%ebx,) \n\t"
  3361.             "jb avg_Alp                  \n\t"
  3362.  
  3363.             : // FIXASM: output regs/vars go here, e.g.:  "=m" (memory_var)
  3364.  
  3365.             : // FIXASM: input regs, e.g.:  "c" (count), "S" (src), "D" (dest)
  3366.  
  3367.             : "%ebx", "%edx", "%edi", "%esi" // CHECKASM: clobber list
  3368.          );
  3369. #endif /* 0 - NEVER REACHED */
  3370.       }
  3371.       break;
  3372.  
  3373.    } // end switch (bpp)
  3374.  
  3375.    __asm__ __volatile__ (
  3376.       // MMX acceleration complete; now do clean-up
  3377.       // check if any remaining bytes left to decode
  3378. #ifdef __PIC__
  3379.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  3380. #endif
  3381.       "movl _MMXLength, %%ebx      \n\t" // ebx:  x == offset bytes after MMX
  3382. //pre "movl row, %%edi             \n\t" // edi:  Avg(x)
  3383.       "cmpl _FullLength, %%ebx     \n\t" // test if offset at end of array
  3384.       "jnb avg_end                 \n\t"
  3385.  
  3386.       // do Avg decode for remaining bytes
  3387. //pre "movl prev_row, %%esi        \n\t" // esi:  Prior(x)
  3388.       "movl %%edi, %%edx           \n\t"
  3389. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  3390.       "subl %%ecx, %%edx           \n\t" // edx:  Raw(x-bpp)
  3391.       "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx below
  3392.  
  3393.    "avg_lp2:                       \n\t"
  3394.       // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
  3395.       "xorl %%eax, %%eax           \n\t"
  3396.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load cl with Prior(x)
  3397.       "movb (%%edx,%%ebx,), %%al   \n\t" // load al with Raw(x-bpp)
  3398.       "addw %%cx, %%ax             \n\t"
  3399.       "incl %%ebx                  \n\t"
  3400.       "shrw %%ax                   \n\t" // divide by 2
  3401.       "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx
  3402.       "cmpl _FullLength, %%ebx     \n\t" // check if at end of array
  3403.       "movb %%al, -1(%%edi,%%ebx,) \n\t" // write back Raw(x) [mov does not
  3404.       "jb avg_lp2                  \n\t" //  affect flags; -1 to offset inc ebx]
  3405.  
  3406.    "avg_end:                       \n\t"
  3407.       "EMMS                        \n\t" // end MMX; prep for poss. FP instrs.
  3408. #ifdef __PIC__
  3409.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  3410. #endif
  3411.  
  3412.       : "=c" (dummy_value_c),            // output regs (dummy)
  3413.         "=S" (dummy_value_S),
  3414.         "=D" (dummy_value_D)
  3415.  
  3416.       : "0" (bpp),       // ecx          // input regs
  3417.         "1" (prev_row),  // esi
  3418.         "2" (row)        // edi
  3419.  
  3420.       : "%eax", "%edx"                   // clobber list
  3421. #ifndef __PIC__
  3422.       , "%ebx"
  3423. #endif
  3424.    );
  3425.  
  3426. } /* end png_read_filter_row_mmx_avg() */
  3427. #endif
  3428.  
  3429.  
  3430.  
  3431. #ifdef PNG_THREAD_UNSAFE_OK
  3432. //===========================================================================//
  3433. //                                                                           //
  3434. //         P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H         //
  3435. //                                                                           //
  3436. //===========================================================================//
  3437.  
  3438. // Optimized code for PNG Paeth filter decoder
  3439.  
  3440. static void /* PRIVATE */
  3441. png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
  3442.                               png_bytep prev_row)
  3443. {
  3444.    int bpp;
  3445.    int dummy_value_c;   // fix 'forbidden register 2 (cx) was spilled' error
  3446.    int dummy_value_S;
  3447.    int dummy_value_D;
  3448.  
  3449.    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
  3450.    _FullLength  = row_info->rowbytes; // # of bytes to filter
  3451.  
  3452.    __asm__ __volatile__ (
  3453. #ifdef __PIC__
  3454.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  3455. #endif
  3456.       "xorl %%ebx, %%ebx           \n\t" // ebx:  x offset
  3457. //pre "movl row, %%edi             \n\t"
  3458.       "xorl %%edx, %%edx           \n\t" // edx:  x-bpp offset
  3459. //pre "movl prev_row, %%esi        \n\t"
  3460.       "xorl %%eax, %%eax           \n\t"
  3461.  
  3462.       // Compute the Raw value for the first bpp bytes
  3463.       // Note: the formula works out to be always
  3464.       //   Paeth(x) = Raw(x) + Prior(x)      where x < bpp
  3465.    "paeth_rlp:                     \n\t"
  3466.       "movb (%%edi,%%ebx,), %%al   \n\t"
  3467.       "addb (%%esi,%%ebx,), %%al   \n\t"
  3468.       "incl %%ebx                  \n\t"
  3469. //pre "cmpl bpp, %%ebx             \n\t" (bpp is preloaded into ecx)
  3470.       "cmpl %%ecx, %%ebx           \n\t"
  3471.       "movb %%al, -1(%%edi,%%ebx,) \n\t"
  3472.       "jb paeth_rlp                \n\t"
  3473.       // get # of bytes to alignment
  3474.       "movl %%edi, _dif            \n\t" // take start of row
  3475.       "addl %%ebx, _dif            \n\t" // add bpp
  3476.       "xorl %%ecx, %%ecx           \n\t"
  3477.       "addl $0xf, _dif             \n\t" // add 7 + 8 to incr past alignment
  3478.                                          // boundary
  3479.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  3480.       "subl %%edi, _dif            \n\t" // subtract from start ==> value ebx
  3481.                                          // at alignment
  3482.       "jz paeth_go                 \n\t"
  3483.       // fix alignment
  3484.  
  3485.    "paeth_lp1:                     \n\t"
  3486.       "xorl %%eax, %%eax           \n\t"
  3487.       // pav = p - a = (a + b - c) - a = b - c
  3488.       "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  3489.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3490.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  3491.       "movl %%eax, _patemp         \n\t" // Save pav for later use
  3492.       "xorl %%eax, %%eax           \n\t"
  3493.       // pbv = p - b = (a + b - c) - b = a - c
  3494.       "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  3495.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  3496.       "movl %%eax, %%ecx           \n\t"
  3497.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3498.       "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  3499.       // pc = abs(pcv)
  3500.       "testl $0x80000000, %%eax    \n\t"
  3501.       "jz paeth_pca                \n\t"
  3502.       "negl %%eax                  \n\t" // reverse sign of neg values
  3503.  
  3504.    "paeth_pca:                     \n\t"
  3505.       "movl %%eax, _pctemp         \n\t" // save pc for later use
  3506.       // pb = abs(pbv)
  3507.       "testl $0x80000000, %%ecx    \n\t"
  3508.       "jz paeth_pba                \n\t"
  3509.       "negl %%ecx                  \n\t" // reverse sign of neg values
  3510.  
  3511.    "paeth_pba:                     \n\t"
  3512.       "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  3513.       // pa = abs(pav)
  3514.       "movl _patemp, %%eax         \n\t"
  3515.       "testl $0x80000000, %%eax    \n\t"
  3516.       "jz paeth_paa                \n\t"
  3517.       "negl %%eax                  \n\t" // reverse sign of neg values
  3518.  
  3519.    "paeth_paa:                     \n\t"
  3520.       "movl %%eax, _patemp         \n\t" // save pa for later use
  3521.       // test if pa <= pb
  3522.       "cmpl %%ecx, %%eax           \n\t"
  3523.       "jna paeth_abb               \n\t"
  3524.       // pa > pb; now test if pb <= pc
  3525.       "cmpl _pctemp, %%ecx         \n\t"
  3526.       "jna paeth_bbc               \n\t"
  3527.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  3528.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3529.       "jmp paeth_paeth             \n\t"
  3530.  
  3531.    "paeth_bbc:                     \n\t"
  3532.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  3533.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  3534.       "jmp paeth_paeth             \n\t"
  3535.  
  3536.    "paeth_abb:                     \n\t"
  3537.       // pa <= pb; now test if pa <= pc
  3538.       "cmpl _pctemp, %%eax         \n\t"
  3539.       "jna paeth_abc               \n\t"
  3540.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  3541.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  3542.       "jmp paeth_paeth             \n\t"
  3543.  
  3544.    "paeth_abc:                     \n\t"
  3545.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  3546.       "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  3547.  
  3548.    "paeth_paeth:                   \n\t"
  3549.       "incl %%ebx                  \n\t"
  3550.       "incl %%edx                  \n\t"
  3551.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  3552.       "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  3553.       "cmpl _dif, %%ebx            \n\t"
  3554.       "jb paeth_lp1                \n\t"
  3555.  
  3556.    "paeth_go:                      \n\t"
  3557.       "movl _FullLength, %%ecx     \n\t"
  3558.       "movl %%ecx, %%eax           \n\t"
  3559.       "subl %%ebx, %%eax           \n\t" // subtract alignment fix
  3560.       "andl $0x00000007, %%eax     \n\t" // calc bytes over mult of 8
  3561.       "subl %%eax, %%ecx           \n\t" // drop over bytes from original length
  3562.       "movl %%ecx, _MMXLength      \n\t"
  3563. #ifdef __PIC__
  3564.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  3565. #endif
  3566.  
  3567.       : "=c" (dummy_value_c),            // output regs (dummy)
  3568.         "=S" (dummy_value_S),
  3569.         "=D" (dummy_value_D)
  3570.  
  3571.       : "0" (bpp),       // ecx          // input regs
  3572.         "1" (prev_row),  // esi
  3573.         "2" (row)        // edi
  3574.  
  3575.       : "%eax", "%edx"                   // clobber list
  3576. #ifndef __PIC__
  3577.       , "%ebx"
  3578. #endif
  3579.    );
  3580.  
  3581.    // now do the math for the rest of the row
  3582.    switch (bpp)
  3583.    {
  3584.       case 3:
  3585.       {
  3586.          _ActiveMask.use = 0x0000000000ffffffLL;
  3587.          _ActiveMaskEnd.use = 0xffff000000000000LL;
  3588.          _ShiftBpp.use = 24;    // == bpp(3) * 8
  3589.          _ShiftRem.use = 40;    // == 64 - 24
  3590.  
  3591.          __asm__ __volatile__ (
  3592.             "movl _dif, %%ecx            \n\t"
  3593. // preload  "movl row, %%edi             \n\t"
  3594. // preload  "movl prev_row, %%esi        \n\t"
  3595.             "pxor %%mm0, %%mm0           \n\t"
  3596.             // prime the pump:  load the first Raw(x-bpp) data set
  3597.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3598.          "paeth_3lp:                     \n\t"
  3599.             "psrlq _ShiftRem, %%mm1      \n\t" // shift last 3 bytes to 1st
  3600.                                                // 3 bytes
  3601.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3602.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3603.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes
  3604.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3605.             "psrlq _ShiftRem, %%mm3      \n\t" // shift last 3 bytes to 1st
  3606.                                                // 3 bytes
  3607.             // pav = p - a = (a + b - c) - a = b - c
  3608.             "movq %%mm2, %%mm4           \n\t"
  3609.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3610.             // pbv = p - b = (a + b - c) - b = a - c
  3611.             "movq %%mm1, %%mm5           \n\t"
  3612.             "psubw %%mm3, %%mm4          \n\t"
  3613.             "pxor %%mm7, %%mm7           \n\t"
  3614.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3615.             "movq %%mm4, %%mm6           \n\t"
  3616.             "psubw %%mm3, %%mm5          \n\t"
  3617.  
  3618.             // pa = abs(p-a) = abs(pav)
  3619.             // pb = abs(p-b) = abs(pbv)
  3620.             // pc = abs(p-c) = abs(pcv)
  3621.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3622.             "paddw %%mm5, %%mm6          \n\t"
  3623.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3624.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3625.             "psubw %%mm0, %%mm4          \n\t"
  3626.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3627.             "psubw %%mm0, %%mm4          \n\t"
  3628.             "psubw %%mm7, %%mm5          \n\t"
  3629.             "pxor %%mm0, %%mm0           \n\t"
  3630.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3631.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3632.             "psubw %%mm7, %%mm5          \n\t"
  3633.             "psubw %%mm0, %%mm6          \n\t"
  3634.             //  test pa <= pb
  3635.             "movq %%mm4, %%mm7           \n\t"
  3636.             "psubw %%mm0, %%mm6          \n\t"
  3637.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3638.             "movq %%mm7, %%mm0           \n\t"
  3639.             // use mm7 mask to merge pa & pb
  3640.             "pand %%mm7, %%mm5           \n\t"
  3641.             // use mm0 mask copy to merge a & b
  3642.             "pand %%mm0, %%mm2           \n\t"
  3643.             "pandn %%mm4, %%mm7          \n\t"
  3644.             "pandn %%mm1, %%mm0          \n\t"
  3645.             "paddw %%mm5, %%mm7          \n\t"
  3646.             "paddw %%mm2, %%mm0          \n\t"
  3647.             //  test  ((pa <= pb)? pa:pb) <= pc
  3648.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3649.             "pxor %%mm1, %%mm1           \n\t"
  3650.             "pand %%mm7, %%mm3           \n\t"
  3651.             "pandn %%mm0, %%mm7          \n\t"
  3652.             "paddw %%mm3, %%mm7          \n\t"
  3653.             "pxor %%mm0, %%mm0           \n\t"
  3654.             "packuswb %%mm1, %%mm7       \n\t"
  3655.             "movq (%%esi,%%ecx,), %%mm3  \n\t" // load c=Prior(x-bpp)
  3656.             "pand _ActiveMask, %%mm7     \n\t"
  3657.             "movq %%mm3, %%mm2           \n\t" // load b=Prior(x) step 1
  3658.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  3659.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3660.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3661.             "movq %%mm7, %%mm1           \n\t" // now mm1 will be used as
  3662.                                                // Raw(x-bpp)
  3663.             // now do Paeth for 2nd set of bytes (3-5)
  3664.             "psrlq _ShiftBpp, %%mm2      \n\t" // load b=Prior(x) step 2
  3665.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3666.             "pxor %%mm7, %%mm7           \n\t"
  3667.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3668.             // pbv = p - b = (a + b - c) - b = a - c
  3669.             "movq %%mm1, %%mm5           \n\t"
  3670.             // pav = p - a = (a + b - c) - a = b - c
  3671.             "movq %%mm2, %%mm4           \n\t"
  3672.             "psubw %%mm3, %%mm5          \n\t"
  3673.             "psubw %%mm3, %%mm4          \n\t"
  3674.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
  3675.             //       pav + pbv = pbv + pav
  3676.             "movq %%mm5, %%mm6           \n\t"
  3677.             "paddw %%mm4, %%mm6          \n\t"
  3678.  
  3679.             // pa = abs(p-a) = abs(pav)
  3680.             // pb = abs(p-b) = abs(pbv)
  3681.             // pc = abs(p-c) = abs(pcv)
  3682.             "pcmpgtw %%mm5, %%mm0        \n\t" // create mask pbv bytes < 0
  3683.             "pcmpgtw %%mm4, %%mm7        \n\t" // create mask pav bytes < 0
  3684.             "pand %%mm5, %%mm0           \n\t" // only pbv bytes < 0 in mm0
  3685.             "pand %%mm4, %%mm7           \n\t" // only pav bytes < 0 in mm7
  3686.             "psubw %%mm0, %%mm5          \n\t"
  3687.             "psubw %%mm7, %%mm4          \n\t"
  3688.             "psubw %%mm0, %%mm5          \n\t"
  3689.             "psubw %%mm7, %%mm4          \n\t"
  3690.             "pxor %%mm0, %%mm0           \n\t"
  3691.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3692.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3693.             "psubw %%mm0, %%mm6          \n\t"
  3694.             //  test pa <= pb
  3695.             "movq %%mm4, %%mm7           \n\t"
  3696.             "psubw %%mm0, %%mm6          \n\t"
  3697.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3698.             "movq %%mm7, %%mm0           \n\t"
  3699.             // use mm7 mask to merge pa & pb
  3700.             "pand %%mm7, %%mm5           \n\t"
  3701.             // use mm0 mask copy to merge a & b
  3702.             "pand %%mm0, %%mm2           \n\t"
  3703.             "pandn %%mm4, %%mm7          \n\t"
  3704.             "pandn %%mm1, %%mm0          \n\t"
  3705.             "paddw %%mm5, %%mm7          \n\t"
  3706.             "paddw %%mm2, %%mm0          \n\t"
  3707.             //  test  ((pa <= pb)? pa:pb) <= pc
  3708.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3709.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3710.             "pand %%mm7, %%mm3           \n\t"
  3711.             "pandn %%mm0, %%mm7          \n\t"
  3712.             "pxor %%mm1, %%mm1           \n\t"
  3713.             "paddw %%mm3, %%mm7          \n\t"
  3714.             "pxor %%mm0, %%mm0           \n\t"
  3715.             "packuswb %%mm1, %%mm7       \n\t"
  3716.             "movq %%mm2, %%mm3           \n\t" // load c=Prior(x-bpp) step 1
  3717.             "pand _ActiveMask, %%mm7     \n\t"
  3718.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3719.             "psllq _ShiftBpp, %%mm7      \n\t" // shift bytes to 2nd group of
  3720.                                                // 3 bytes
  3721.              // pav = p - a = (a + b - c) - a = b - c
  3722.             "movq %%mm2, %%mm4           \n\t"
  3723.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  3724.             "psllq _ShiftBpp, %%mm3      \n\t" // load c=Prior(x-bpp) step 2
  3725.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3726.             "movq %%mm7, %%mm1           \n\t"
  3727.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3728.             "psllq _ShiftBpp, %%mm1      \n\t" // shift bytes
  3729.                                     // now mm1 will be used as Raw(x-bpp)
  3730.             // now do Paeth for 3rd, and final, set of bytes (6-7)
  3731.             "pxor %%mm7, %%mm7           \n\t"
  3732.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3733.             "psubw %%mm3, %%mm4          \n\t"
  3734.             // pbv = p - b = (a + b - c) - b = a - c
  3735.             "movq %%mm1, %%mm5           \n\t"
  3736.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3737.             "movq %%mm4, %%mm6           \n\t"
  3738.             "psubw %%mm3, %%mm5          \n\t"
  3739.             "pxor %%mm0, %%mm0           \n\t"
  3740.             "paddw %%mm5, %%mm6          \n\t"
  3741.  
  3742.             // pa = abs(p-a) = abs(pav)
  3743.             // pb = abs(p-b) = abs(pbv)
  3744.             // pc = abs(p-c) = abs(pcv)
  3745.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3746.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3747.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3748.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3749.             "psubw %%mm0, %%mm4          \n\t"
  3750.             "psubw %%mm7, %%mm5          \n\t"
  3751.             "psubw %%mm0, %%mm4          \n\t"
  3752.             "psubw %%mm7, %%mm5          \n\t"
  3753.             "pxor %%mm0, %%mm0           \n\t"
  3754.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3755.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3756.             "psubw %%mm0, %%mm6          \n\t"
  3757.             //  test pa <= pb
  3758.             "movq %%mm4, %%mm7           \n\t"
  3759.             "psubw %%mm0, %%mm6          \n\t"
  3760.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3761.             "movq %%mm7, %%mm0           \n\t"
  3762.             // use mm0 mask copy to merge a & b
  3763.             "pand %%mm0, %%mm2           \n\t"
  3764.             // use mm7 mask to merge pa & pb
  3765.             "pand %%mm7, %%mm5           \n\t"
  3766.             "pandn %%mm1, %%mm0          \n\t"
  3767.             "pandn %%mm4, %%mm7          \n\t"
  3768.             "paddw %%mm2, %%mm0          \n\t"
  3769.             "paddw %%mm5, %%mm7          \n\t"
  3770.             //  test  ((pa <= pb)? pa:pb) <= pc
  3771.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3772.             "pand %%mm7, %%mm3           \n\t"
  3773.             "pandn %%mm0, %%mm7          \n\t"
  3774.             "paddw %%mm3, %%mm7          \n\t"
  3775.             "pxor %%mm1, %%mm1           \n\t"
  3776.             "packuswb %%mm7, %%mm1       \n\t"
  3777.             // step ecx to next set of 8 bytes and repeat loop til done
  3778.             "addl $8, %%ecx              \n\t"
  3779.             "pand _ActiveMaskEnd, %%mm1  \n\t"
  3780.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with
  3781.                                                  // Raw(x)
  3782.  
  3783.             "cmpl _MMXLength, %%ecx      \n\t"
  3784.             "pxor %%mm0, %%mm0           \n\t" // pxor does not affect flags
  3785.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  3786.                                  // mm1 will be used as Raw(x-bpp) next loop
  3787.                            // mm3 ready to be used as Prior(x-bpp) next loop
  3788.             "jb paeth_3lp                \n\t"
  3789.  
  3790.             : "=S" (dummy_value_S),             // output regs (dummy)
  3791.               "=D" (dummy_value_D)
  3792.  
  3793.             : "0" (prev_row),  // esi           // input regs
  3794.               "1" (row)        // edi
  3795.  
  3796.             : "%ecx"                            // clobber list
  3797. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3798.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3799.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3800. #endif
  3801.          );
  3802.       }
  3803.       break;  // end 3 bpp
  3804.  
  3805.       case 6:
  3806.       //case 7:   // GRR BOGUS
  3807.       //case 5:   // GRR BOGUS
  3808.       {
  3809.          _ActiveMask.use  = 0x00000000ffffffffLL;
  3810.          _ActiveMask2.use = 0xffffffff00000000LL;
  3811.          _ShiftBpp.use = bpp << 3;    // == bpp * 8
  3812.          _ShiftRem.use = 64 - _ShiftBpp.use;
  3813.  
  3814.          __asm__ __volatile__ (
  3815.             "movl _dif, %%ecx            \n\t"
  3816. // preload  "movl row, %%edi             \n\t"
  3817. // preload  "movl prev_row, %%esi        \n\t"
  3818.             // prime the pump:  load the first Raw(x-bpp) data set
  3819.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3820.             "pxor %%mm0, %%mm0           \n\t"
  3821.  
  3822.          "paeth_6lp:                     \n\t"
  3823.             // must shift to position Raw(x-bpp) data
  3824.             "psrlq _ShiftRem, %%mm1      \n\t"
  3825.             // do first set of 4 bytes
  3826.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  3827.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3828.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3829.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  3830.             // must shift to position Prior(x-bpp) data
  3831.             "psrlq _ShiftRem, %%mm3      \n\t"
  3832.             // pav = p - a = (a + b - c) - a = b - c
  3833.             "movq %%mm2, %%mm4           \n\t"
  3834.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack Low bytes of c
  3835.             // pbv = p - b = (a + b - c) - b = a - c
  3836.             "movq %%mm1, %%mm5           \n\t"
  3837.             "psubw %%mm3, %%mm4          \n\t"
  3838.             "pxor %%mm7, %%mm7           \n\t"
  3839.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3840.             "movq %%mm4, %%mm6           \n\t"
  3841.             "psubw %%mm3, %%mm5          \n\t"
  3842.             // pa = abs(p-a) = abs(pav)
  3843.             // pb = abs(p-b) = abs(pbv)
  3844.             // pc = abs(p-c) = abs(pcv)
  3845.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3846.             "paddw %%mm5, %%mm6          \n\t"
  3847.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3848.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3849.             "psubw %%mm0, %%mm4          \n\t"
  3850.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3851.             "psubw %%mm0, %%mm4          \n\t"
  3852.             "psubw %%mm7, %%mm5          \n\t"
  3853.             "pxor %%mm0, %%mm0           \n\t"
  3854.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3855.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3856.             "psubw %%mm7, %%mm5          \n\t"
  3857.             "psubw %%mm0, %%mm6          \n\t"
  3858.             //  test pa <= pb
  3859.             "movq %%mm4, %%mm7           \n\t"
  3860.             "psubw %%mm0, %%mm6          \n\t"
  3861.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3862.             "movq %%mm7, %%mm0           \n\t"
  3863.             // use mm7 mask to merge pa & pb
  3864.             "pand %%mm7, %%mm5           \n\t"
  3865.             // use mm0 mask copy to merge a & b
  3866.             "pand %%mm0, %%mm2           \n\t"
  3867.             "pandn %%mm4, %%mm7          \n\t"
  3868.             "pandn %%mm1, %%mm0          \n\t"
  3869.             "paddw %%mm5, %%mm7          \n\t"
  3870.             "paddw %%mm2, %%mm0          \n\t"
  3871.             //  test  ((pa <= pb)? pa:pb) <= pc
  3872.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3873.             "pxor %%mm1, %%mm1           \n\t"
  3874.             "pand %%mm7, %%mm3           \n\t"
  3875.             "pandn %%mm0, %%mm7          \n\t"
  3876.             "paddw %%mm3, %%mm7          \n\t"
  3877.             "pxor %%mm0, %%mm0           \n\t"
  3878.             "packuswb %%mm1, %%mm7       \n\t"
  3879.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // load c=Prior(x-bpp)
  3880.             "pand _ActiveMask, %%mm7     \n\t"
  3881.             "psrlq _ShiftRem, %%mm3      \n\t"
  3882.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x) step 1
  3883.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor and Raw(x)
  3884.             "movq %%mm2, %%mm6           \n\t"
  3885.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  3886.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t"
  3887.             "psllq _ShiftBpp, %%mm6      \n\t"
  3888.             "movq %%mm7, %%mm5           \n\t"
  3889.             "psrlq _ShiftRem, %%mm1      \n\t"
  3890.             "por %%mm6, %%mm3            \n\t"
  3891.             "psllq _ShiftBpp, %%mm5      \n\t"
  3892.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3893.             "por %%mm5, %%mm1            \n\t"
  3894.             // do second set of 4 bytes
  3895.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3896.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  3897.             // pav = p - a = (a + b - c) - a = b - c
  3898.             "movq %%mm2, %%mm4           \n\t"
  3899.             // pbv = p - b = (a + b - c) - b = a - c
  3900.             "movq %%mm1, %%mm5           \n\t"
  3901.             "psubw %%mm3, %%mm4          \n\t"
  3902.             "pxor %%mm7, %%mm7           \n\t"
  3903.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3904.             "movq %%mm4, %%mm6           \n\t"
  3905.             "psubw %%mm3, %%mm5          \n\t"
  3906.             // pa = abs(p-a) = abs(pav)
  3907.             // pb = abs(p-b) = abs(pbv)
  3908.             // pc = abs(p-c) = abs(pcv)
  3909.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3910.             "paddw %%mm5, %%mm6          \n\t"
  3911.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3912.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  3913.             "psubw %%mm0, %%mm4          \n\t"
  3914.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  3915.             "psubw %%mm0, %%mm4          \n\t"
  3916.             "psubw %%mm7, %%mm5          \n\t"
  3917.             "pxor %%mm0, %%mm0           \n\t"
  3918.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  3919.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  3920.             "psubw %%mm7, %%mm5          \n\t"
  3921.             "psubw %%mm0, %%mm6          \n\t"
  3922.             //  test pa <= pb
  3923.             "movq %%mm4, %%mm7           \n\t"
  3924.             "psubw %%mm0, %%mm6          \n\t"
  3925.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  3926.             "movq %%mm7, %%mm0           \n\t"
  3927.             // use mm7 mask to merge pa & pb
  3928.             "pand %%mm7, %%mm5           \n\t"
  3929.             // use mm0 mask copy to merge a & b
  3930.             "pand %%mm0, %%mm2           \n\t"
  3931.             "pandn %%mm4, %%mm7          \n\t"
  3932.             "pandn %%mm1, %%mm0          \n\t"
  3933.             "paddw %%mm5, %%mm7          \n\t"
  3934.             "paddw %%mm2, %%mm0          \n\t"
  3935.             //  test  ((pa <= pb)? pa:pb) <= pc
  3936.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  3937.             "pxor %%mm1, %%mm1           \n\t"
  3938.             "pand %%mm7, %%mm3           \n\t"
  3939.             "pandn %%mm0, %%mm7          \n\t"
  3940.             "pxor %%mm1, %%mm1           \n\t"
  3941.             "paddw %%mm3, %%mm7          \n\t"
  3942.             "pxor %%mm0, %%mm0           \n\t"
  3943.             // step ecx to next set of 8 bytes and repeat loop til done
  3944.             "addl $8, %%ecx              \n\t"
  3945.             "packuswb %%mm7, %%mm1       \n\t"
  3946.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
  3947.             "cmpl _MMXLength, %%ecx      \n\t"
  3948.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  3949.                                 // mm1 will be used as Raw(x-bpp) next loop
  3950.             "jb paeth_6lp                \n\t"
  3951.  
  3952.             : "=S" (dummy_value_S),             // output regs (dummy)
  3953.               "=D" (dummy_value_D)
  3954.  
  3955.             : "0" (prev_row),  // esi           // input regs
  3956.               "1" (row)        // edi
  3957.  
  3958.             : "%ecx"                            // clobber list
  3959. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  3960.             , "%mm0", "%mm1", "%mm2", "%mm3"
  3961.             , "%mm4", "%mm5", "%mm6", "%mm7"
  3962. #endif
  3963.          );
  3964.       }
  3965.       break;  // end 6 bpp
  3966.  
  3967.       case 4:
  3968.       {
  3969.          _ActiveMask.use  = 0x00000000ffffffffLL;
  3970.  
  3971.          __asm__ __volatile__ (
  3972.             "movl _dif, %%ecx            \n\t"
  3973. // preload  "movl row, %%edi             \n\t"
  3974. // preload  "movl prev_row, %%esi        \n\t"
  3975.             "pxor %%mm0, %%mm0           \n\t"
  3976.             // prime the pump:  load the first Raw(x-bpp) data set
  3977.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
  3978.                                      //  a=Raw(x-bpp) bytes
  3979.          "paeth_4lp:                     \n\t"
  3980.             // do first set of 4 bytes
  3981.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  3982.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  3983.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  3984.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  3985.             // pav = p - a = (a + b - c) - a = b - c
  3986.             "movq %%mm2, %%mm4           \n\t"
  3987.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  3988.             // pbv = p - b = (a + b - c) - b = a - c
  3989.             "movq %%mm1, %%mm5           \n\t"
  3990.             "psubw %%mm3, %%mm4          \n\t"
  3991.             "pxor %%mm7, %%mm7           \n\t"
  3992.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  3993.             "movq %%mm4, %%mm6           \n\t"
  3994.             "psubw %%mm3, %%mm5          \n\t"
  3995.             // pa = abs(p-a) = abs(pav)
  3996.             // pb = abs(p-b) = abs(pbv)
  3997.             // pc = abs(p-c) = abs(pcv)
  3998.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  3999.             "paddw %%mm5, %%mm6          \n\t"
  4000.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4001.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  4002.             "psubw %%mm0, %%mm4          \n\t"
  4003.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  4004.             "psubw %%mm0, %%mm4          \n\t"
  4005.             "psubw %%mm7, %%mm5          \n\t"
  4006.             "pxor %%mm0, %%mm0           \n\t"
  4007.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  4008.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4009.             "psubw %%mm7, %%mm5          \n\t"
  4010.             "psubw %%mm0, %%mm6          \n\t"
  4011.             //  test pa <= pb
  4012.             "movq %%mm4, %%mm7           \n\t"
  4013.             "psubw %%mm0, %%mm6          \n\t"
  4014.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  4015.             "movq %%mm7, %%mm0           \n\t"
  4016.             // use mm7 mask to merge pa & pb
  4017.             "pand %%mm7, %%mm5           \n\t"
  4018.             // use mm0 mask copy to merge a & b
  4019.             "pand %%mm0, %%mm2           \n\t"
  4020.             "pandn %%mm4, %%mm7          \n\t"
  4021.             "pandn %%mm1, %%mm0          \n\t"
  4022.             "paddw %%mm5, %%mm7          \n\t"
  4023.             "paddw %%mm2, %%mm0          \n\t"
  4024.             //  test  ((pa <= pb)? pa:pb) <= pc
  4025.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4026.             "pxor %%mm1, %%mm1           \n\t"
  4027.             "pand %%mm7, %%mm3           \n\t"
  4028.             "pandn %%mm0, %%mm7          \n\t"
  4029.             "paddw %%mm3, %%mm7          \n\t"
  4030.             "pxor %%mm0, %%mm0           \n\t"
  4031.             "packuswb %%mm1, %%mm7       \n\t"
  4032.             "movq (%%esi,%%ecx,), %%mm3  \n\t" // load c=Prior(x-bpp)
  4033.             "pand _ActiveMask, %%mm7     \n\t"
  4034.             "movq %%mm3, %%mm2           \n\t" // load b=Prior(x) step 1
  4035.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  4036.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  4037.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  4038.             "movq %%mm7, %%mm1           \n\t" // now mm1 will be used as Raw(x-bpp)
  4039.             // do second set of 4 bytes
  4040.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  4041.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  4042.             // pav = p - a = (a + b - c) - a = b - c
  4043.             "movq %%mm2, %%mm4           \n\t"
  4044.             // pbv = p - b = (a + b - c) - b = a - c
  4045.             "movq %%mm1, %%mm5           \n\t"
  4046.             "psubw %%mm3, %%mm4          \n\t"
  4047.             "pxor %%mm7, %%mm7           \n\t"
  4048.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4049.             "movq %%mm4, %%mm6           \n\t"
  4050.             "psubw %%mm3, %%mm5          \n\t"
  4051.             // pa = abs(p-a) = abs(pav)
  4052.             // pb = abs(p-b) = abs(pbv)
  4053.             // pc = abs(p-c) = abs(pcv)
  4054.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  4055.             "paddw %%mm5, %%mm6          \n\t"
  4056.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4057.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  4058.             "psubw %%mm0, %%mm4          \n\t"
  4059.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  4060.             "psubw %%mm0, %%mm4          \n\t"
  4061.             "psubw %%mm7, %%mm5          \n\t"
  4062.             "pxor %%mm0, %%mm0           \n\t"
  4063.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  4064.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4065.             "psubw %%mm7, %%mm5          \n\t"
  4066.             "psubw %%mm0, %%mm6          \n\t"
  4067.             //  test pa <= pb
  4068.             "movq %%mm4, %%mm7           \n\t"
  4069.             "psubw %%mm0, %%mm6          \n\t"
  4070.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  4071.             "movq %%mm7, %%mm0           \n\t"
  4072.             // use mm7 mask to merge pa & pb
  4073.             "pand %%mm7, %%mm5           \n\t"
  4074.             // use mm0 mask copy to merge a & b
  4075.             "pand %%mm0, %%mm2           \n\t"
  4076.             "pandn %%mm4, %%mm7          \n\t"
  4077.             "pandn %%mm1, %%mm0          \n\t"
  4078.             "paddw %%mm5, %%mm7          \n\t"
  4079.             "paddw %%mm2, %%mm0          \n\t"
  4080.             //  test  ((pa <= pb)? pa:pb) <= pc
  4081.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4082.             "pxor %%mm1, %%mm1           \n\t"
  4083.             "pand %%mm7, %%mm3           \n\t"
  4084.             "pandn %%mm0, %%mm7          \n\t"
  4085.             "pxor %%mm1, %%mm1           \n\t"
  4086.             "paddw %%mm3, %%mm7          \n\t"
  4087.             "pxor %%mm0, %%mm0           \n\t"
  4088.             // step ecx to next set of 8 bytes and repeat loop til done
  4089.             "addl $8, %%ecx              \n\t"
  4090.             "packuswb %%mm7, %%mm1       \n\t"
  4091.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add predictor with Raw(x)
  4092.             "cmpl _MMXLength, %%ecx      \n\t"
  4093.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  4094.                                 // mm1 will be used as Raw(x-bpp) next loop
  4095.             "jb paeth_4lp                \n\t"
  4096.  
  4097.             : "=S" (dummy_value_S),             // output regs (dummy)
  4098.               "=D" (dummy_value_D)
  4099.  
  4100.             : "0" (prev_row),  // esi           // input regs
  4101.               "1" (row)        // edi
  4102.  
  4103.             : "%ecx"                            // clobber list
  4104. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  4105.             , "%mm0", "%mm1", "%mm2", "%mm3"
  4106.             , "%mm4", "%mm5", "%mm6", "%mm7"
  4107. #endif
  4108.          );
  4109.       }
  4110.       break;  // end 4 bpp
  4111.  
  4112.       case 8:                          // bpp == 8
  4113.       {
  4114.          _ActiveMask.use  = 0x00000000ffffffffLL;
  4115.  
  4116.          __asm__ __volatile__ (
  4117.             "movl _dif, %%ecx            \n\t"
  4118. // preload  "movl row, %%edi             \n\t"
  4119. // preload  "movl prev_row, %%esi        \n\t"
  4120.             "pxor %%mm0, %%mm0           \n\t"
  4121.             // prime the pump:  load the first Raw(x-bpp) data set
  4122.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // only time should need to read
  4123.                                        //  a=Raw(x-bpp) bytes
  4124.          "paeth_8lp:                     \n\t"
  4125.             // do first set of 4 bytes
  4126.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  4127.             "punpcklbw %%mm0, %%mm1      \n\t" // unpack Low bytes of a
  4128.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  4129.             "punpcklbw %%mm0, %%mm2      \n\t" // unpack Low bytes of b
  4130.             // pav = p - a = (a + b - c) - a = b - c
  4131.             "movq %%mm2, %%mm4           \n\t"
  4132.             "punpcklbw %%mm0, %%mm3      \n\t" // unpack Low bytes of c
  4133.             // pbv = p - b = (a + b - c) - b = a - c
  4134.             "movq %%mm1, %%mm5           \n\t"
  4135.             "psubw %%mm3, %%mm4          \n\t"
  4136.             "pxor %%mm7, %%mm7           \n\t"
  4137.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4138.             "movq %%mm4, %%mm6           \n\t"
  4139.             "psubw %%mm3, %%mm5          \n\t"
  4140.             // pa = abs(p-a) = abs(pav)
  4141.             // pb = abs(p-b) = abs(pbv)
  4142.             // pc = abs(p-c) = abs(pcv)
  4143.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  4144.             "paddw %%mm5, %%mm6          \n\t"
  4145.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4146.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  4147.             "psubw %%mm0, %%mm4          \n\t"
  4148.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  4149.             "psubw %%mm0, %%mm4          \n\t"
  4150.             "psubw %%mm7, %%mm5          \n\t"
  4151.             "pxor %%mm0, %%mm0           \n\t"
  4152.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  4153.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4154.             "psubw %%mm7, %%mm5          \n\t"
  4155.             "psubw %%mm0, %%mm6          \n\t"
  4156.             //  test pa <= pb
  4157.             "movq %%mm4, %%mm7           \n\t"
  4158.             "psubw %%mm0, %%mm6          \n\t"
  4159.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  4160.             "movq %%mm7, %%mm0           \n\t"
  4161.             // use mm7 mask to merge pa & pb
  4162.             "pand %%mm7, %%mm5           \n\t"
  4163.             // use mm0 mask copy to merge a & b
  4164.             "pand %%mm0, %%mm2           \n\t"
  4165.             "pandn %%mm4, %%mm7          \n\t"
  4166.             "pandn %%mm1, %%mm0          \n\t"
  4167.             "paddw %%mm5, %%mm7          \n\t"
  4168.             "paddw %%mm2, %%mm0          \n\t"
  4169.             //  test  ((pa <= pb)? pa:pb) <= pc
  4170.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4171.             "pxor %%mm1, %%mm1           \n\t"
  4172.             "pand %%mm7, %%mm3           \n\t"
  4173.             "pandn %%mm0, %%mm7          \n\t"
  4174.             "paddw %%mm3, %%mm7          \n\t"
  4175.             "pxor %%mm0, %%mm0           \n\t"
  4176.             "packuswb %%mm1, %%mm7       \n\t"
  4177.             "movq -8(%%esi,%%ecx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
  4178.             "pand _ActiveMask, %%mm7     \n\t"
  4179.             "movq (%%esi,%%ecx,), %%mm2  \n\t" // load b=Prior(x)
  4180.             "paddb (%%edi,%%ecx,), %%mm7 \n\t" // add Paeth predictor with Raw(x)
  4181.             "punpckhbw %%mm0, %%mm3      \n\t" // unpack High bytes of c
  4182.             "movq %%mm7, (%%edi,%%ecx,)  \n\t" // write back updated value
  4183.             "movq -8(%%edi,%%ecx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes
  4184.  
  4185.             // do second set of 4 bytes
  4186.             "punpckhbw %%mm0, %%mm2      \n\t" // unpack High bytes of b
  4187.             "punpckhbw %%mm0, %%mm1      \n\t" // unpack High bytes of a
  4188.             // pav = p - a = (a + b - c) - a = b - c
  4189.             "movq %%mm2, %%mm4           \n\t"
  4190.             // pbv = p - b = (a + b - c) - b = a - c
  4191.             "movq %%mm1, %%mm5           \n\t"
  4192.             "psubw %%mm3, %%mm4          \n\t"
  4193.             "pxor %%mm7, %%mm7           \n\t"
  4194.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4195.             "movq %%mm4, %%mm6           \n\t"
  4196.             "psubw %%mm3, %%mm5          \n\t"
  4197.             // pa = abs(p-a) = abs(pav)
  4198.             // pb = abs(p-b) = abs(pbv)
  4199.             // pc = abs(p-c) = abs(pcv)
  4200.             "pcmpgtw %%mm4, %%mm0        \n\t" // create mask pav bytes < 0
  4201.             "paddw %%mm5, %%mm6          \n\t"
  4202.             "pand %%mm4, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4203.             "pcmpgtw %%mm5, %%mm7        \n\t" // create mask pbv bytes < 0
  4204.             "psubw %%mm0, %%mm4          \n\t"
  4205.             "pand %%mm5, %%mm7           \n\t" // only pbv bytes < 0 in mm0
  4206.             "psubw %%mm0, %%mm4          \n\t"
  4207.             "psubw %%mm7, %%mm5          \n\t"
  4208.             "pxor %%mm0, %%mm0           \n\t"
  4209.             "pcmpgtw %%mm6, %%mm0        \n\t" // create mask pcv bytes < 0
  4210.             "pand %%mm6, %%mm0           \n\t" // only pav bytes < 0 in mm7
  4211.             "psubw %%mm7, %%mm5          \n\t"
  4212.             "psubw %%mm0, %%mm6          \n\t"
  4213.             //  test pa <= pb
  4214.             "movq %%mm4, %%mm7           \n\t"
  4215.             "psubw %%mm0, %%mm6          \n\t"
  4216.             "pcmpgtw %%mm5, %%mm7        \n\t" // pa > pb?
  4217.             "movq %%mm7, %%mm0           \n\t"
  4218.             // use mm7 mask to merge pa & pb
  4219.             "pand %%mm7, %%mm5           \n\t"
  4220.             // use mm0 mask copy to merge a & b
  4221.             "pand %%mm0, %%mm2           \n\t"
  4222.             "pandn %%mm4, %%mm7          \n\t"
  4223.             "pandn %%mm1, %%mm0          \n\t"
  4224.             "paddw %%mm5, %%mm7          \n\t"
  4225.             "paddw %%mm2, %%mm0          \n\t"
  4226.             //  test  ((pa <= pb)? pa:pb) <= pc
  4227.             "pcmpgtw %%mm6, %%mm7        \n\t" // pab > pc?
  4228.             "pxor %%mm1, %%mm1           \n\t"
  4229.             "pand %%mm7, %%mm3           \n\t"
  4230.             "pandn %%mm0, %%mm7          \n\t"
  4231.             "pxor %%mm1, %%mm1           \n\t"
  4232.             "paddw %%mm3, %%mm7          \n\t"
  4233.             "pxor %%mm0, %%mm0           \n\t"
  4234.             // step ecx to next set of 8 bytes and repeat loop til done
  4235.             "addl $8, %%ecx              \n\t"
  4236.             "packuswb %%mm7, %%mm1       \n\t"
  4237.             "paddb -8(%%edi,%%ecx,), %%mm1 \n\t" // add Paeth predictor with Raw(x)
  4238.             "cmpl _MMXLength, %%ecx      \n\t"
  4239.             "movq %%mm1, -8(%%edi,%%ecx,) \n\t" // write back updated value
  4240.                             // mm1 will be used as Raw(x-bpp) next loop
  4241.             "jb paeth_8lp                \n\t"
  4242.  
  4243.             : "=S" (dummy_value_S),             // output regs (dummy)
  4244.               "=D" (dummy_value_D)
  4245.  
  4246.             : "0" (prev_row),  // esi           // input regs
  4247.               "1" (row)        // edi
  4248.  
  4249.             : "%ecx"                            // clobber list
  4250. #if 0  /* %mm0, ..., %mm7 not supported by gcc 2.7.2.3 or egcs 1.1 */
  4251.             , "%mm0", "%mm1", "%mm2", "%mm3"
  4252.             , "%mm4", "%mm5", "%mm6", "%mm7"
  4253. #endif
  4254.          );
  4255.       }
  4256.       break;  // end 8 bpp
  4257.  
  4258.       case 1:                // bpp = 1
  4259.       case 2:                // bpp = 2
  4260.       default:               // bpp > 8
  4261.       {
  4262.          __asm__ __volatile__ (
  4263. #ifdef __PIC__
  4264.             "pushl %%ebx                 \n\t" // save Global Offset Table index
  4265. #endif
  4266.             "movl _dif, %%ebx            \n\t"
  4267.             "cmpl _FullLength, %%ebx     \n\t"
  4268.             "jnb paeth_dend              \n\t"
  4269.  
  4270. // preload  "movl row, %%edi             \n\t"
  4271. // preload  "movl prev_row, %%esi        \n\t"
  4272.             // do Paeth decode for remaining bytes
  4273.             "movl %%ebx, %%edx           \n\t"
  4274. // preload  "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  4275.             "subl %%ecx, %%edx           \n\t" // edx = ebx - bpp
  4276.             "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx
  4277.  
  4278.          "paeth_dlp:                     \n\t"
  4279.             "xorl %%eax, %%eax           \n\t"
  4280.             // pav = p - a = (a + b - c) - a = b - c
  4281.             "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  4282.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4283.             "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4284.             "movl %%eax, _patemp         \n\t" // Save pav for later use
  4285.             "xorl %%eax, %%eax           \n\t"
  4286.             // pbv = p - b = (a + b - c) - b = a - c
  4287.             "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  4288.             "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4289.             "movl %%eax, %%ecx           \n\t"
  4290.             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4291.             "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  4292.             // pc = abs(pcv)
  4293.             "testl $0x80000000, %%eax    \n\t"
  4294.             "jz paeth_dpca               \n\t"
  4295.             "negl %%eax                  \n\t" // reverse sign of neg values
  4296.  
  4297.          "paeth_dpca:                    \n\t"
  4298.             "movl %%eax, _pctemp         \n\t" // save pc for later use
  4299.             // pb = abs(pbv)
  4300.             "testl $0x80000000, %%ecx    \n\t"
  4301.             "jz paeth_dpba               \n\t"
  4302.             "negl %%ecx                  \n\t" // reverse sign of neg values
  4303.  
  4304.          "paeth_dpba:                    \n\t"
  4305.             "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  4306.             // pa = abs(pav)
  4307.             "movl _patemp, %%eax         \n\t"
  4308.             "testl $0x80000000, %%eax    \n\t"
  4309.             "jz paeth_dpaa               \n\t"
  4310.             "negl %%eax                  \n\t" // reverse sign of neg values
  4311.  
  4312.          "paeth_dpaa:                    \n\t"
  4313.             "movl %%eax, _patemp         \n\t" // save pa for later use
  4314.             // test if pa <= pb
  4315.             "cmpl %%ecx, %%eax           \n\t"
  4316.             "jna paeth_dabb              \n\t"
  4317.             // pa > pb; now test if pb <= pc
  4318.             "cmpl _pctemp, %%ecx         \n\t"
  4319.             "jna paeth_dbbc              \n\t"
  4320.             // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4321.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4322.             "jmp paeth_dpaeth            \n\t"
  4323.  
  4324.          "paeth_dbbc:                    \n\t"
  4325.             // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  4326.             "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  4327.             "jmp paeth_dpaeth            \n\t"
  4328.  
  4329.          "paeth_dabb:                    \n\t"
  4330.             // pa <= pb; now test if pa <= pc
  4331.             "cmpl _pctemp, %%eax         \n\t"
  4332.             "jna paeth_dabc              \n\t"
  4333.             // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4334.             "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4335.             "jmp paeth_dpaeth            \n\t"
  4336.  
  4337.          "paeth_dabc:                    \n\t"
  4338.             // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  4339.             "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  4340.  
  4341.          "paeth_dpaeth:                  \n\t"
  4342.             "incl %%ebx                  \n\t"
  4343.             "incl %%edx                  \n\t"
  4344.             // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  4345.             "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  4346.             "cmpl _FullLength, %%ebx     \n\t"
  4347.             "jb paeth_dlp                \n\t"
  4348.  
  4349.          "paeth_dend:                    \n\t"
  4350. #ifdef __PIC__
  4351.             "popl %%ebx                  \n\t" // index to Global Offset Table
  4352. #endif
  4353.  
  4354.             : "=c" (dummy_value_c),            // output regs (dummy)
  4355.               "=S" (dummy_value_S),
  4356.               "=D" (dummy_value_D)
  4357.  
  4358.             : "0" (bpp),       // ecx          // input regs
  4359.               "1" (prev_row),  // esi
  4360.               "2" (row)        // edi
  4361.  
  4362.             : "%eax", "%edx"                   // clobber list
  4363. #ifndef __PIC__
  4364.             , "%ebx"
  4365. #endif
  4366.          );
  4367.       }
  4368.       return;                   // No need to go further with this one
  4369.  
  4370.    } // end switch (bpp)
  4371.  
  4372.    __asm__ __volatile__ (
  4373.       // MMX acceleration complete; now do clean-up
  4374.       // check if any remaining bytes left to decode
  4375. #ifdef __PIC__
  4376.       "pushl %%ebx                 \n\t" // save index to Global Offset Table
  4377. #endif
  4378.       "movl _MMXLength, %%ebx      \n\t"
  4379.       "cmpl _FullLength, %%ebx     \n\t"
  4380.       "jnb paeth_end               \n\t"
  4381. //pre "movl row, %%edi             \n\t"
  4382. //pre "movl prev_row, %%esi        \n\t"
  4383.       // do Paeth decode for remaining bytes
  4384.       "movl %%ebx, %%edx           \n\t"
  4385. //pre "subl bpp, %%edx             \n\t" // (bpp is preloaded into ecx)
  4386.       "subl %%ecx, %%edx           \n\t" // edx = ebx - bpp
  4387.       "xorl %%ecx, %%ecx           \n\t" // zero ecx before using cl & cx below
  4388.  
  4389.    "paeth_lp2:                     \n\t"
  4390.       "xorl %%eax, %%eax           \n\t"
  4391.       // pav = p - a = (a + b - c) - a = b - c
  4392.       "movb (%%esi,%%ebx,), %%al   \n\t" // load Prior(x) into al
  4393.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4394.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4395.       "movl %%eax, _patemp         \n\t" // Save pav for later use
  4396.       "xorl %%eax, %%eax           \n\t"
  4397.       // pbv = p - b = (a + b - c) - b = a - c
  4398.       "movb (%%edi,%%edx,), %%al   \n\t" // load Raw(x-bpp) into al
  4399.       "subl %%ecx, %%eax           \n\t" // subtract Prior(x-bpp)
  4400.       "movl %%eax, %%ecx           \n\t"
  4401.       // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
  4402.       "addl _patemp, %%eax         \n\t" // pcv = pav + pbv
  4403.       // pc = abs(pcv)
  4404.       "testl $0x80000000, %%eax    \n\t"
  4405.       "jz paeth_pca2               \n\t"
  4406.       "negl %%eax                  \n\t" // reverse sign of neg values
  4407.  
  4408.    "paeth_pca2:                    \n\t"
  4409.       "movl %%eax, _pctemp         \n\t" // save pc for later use
  4410.       // pb = abs(pbv)
  4411.       "testl $0x80000000, %%ecx    \n\t"
  4412.       "jz paeth_pba2               \n\t"
  4413.       "negl %%ecx                  \n\t" // reverse sign of neg values
  4414.  
  4415.    "paeth_pba2:                    \n\t"
  4416.       "movl %%ecx, _pbtemp         \n\t" // save pb for later use
  4417.       // pa = abs(pav)
  4418.       "movl _patemp, %%eax         \n\t"
  4419.       "testl $0x80000000, %%eax    \n\t"
  4420.       "jz paeth_paa2               \n\t"
  4421.       "negl %%eax                  \n\t" // reverse sign of neg values
  4422.  
  4423.    "paeth_paa2:                    \n\t"
  4424.       "movl %%eax, _patemp         \n\t" // save pa for later use
  4425.       // test if pa <= pb
  4426.       "cmpl %%ecx, %%eax           \n\t"
  4427.       "jna paeth_abb2              \n\t"
  4428.       // pa > pb; now test if pb <= pc
  4429.       "cmpl _pctemp, %%ecx         \n\t"
  4430.       "jna paeth_bbc2              \n\t"
  4431.       // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4432.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4433.       "jmp paeth_paeth2            \n\t"
  4434.  
  4435.    "paeth_bbc2:                    \n\t"
  4436.       // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
  4437.       "movb (%%esi,%%ebx,), %%cl   \n\t" // load Prior(x) into cl
  4438.       "jmp paeth_paeth2            \n\t"
  4439.  
  4440.    "paeth_abb2:                    \n\t"
  4441.       // pa <= pb; now test if pa <= pc
  4442.       "cmpl _pctemp, %%eax         \n\t"
  4443.       "jna paeth_abc2              \n\t"
  4444.       // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
  4445.       "movb (%%esi,%%edx,), %%cl   \n\t" // load Prior(x-bpp) into cl
  4446.       "jmp paeth_paeth2            \n\t"
  4447.  
  4448.    "paeth_abc2:                    \n\t"
  4449.       // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
  4450.       "movb (%%edi,%%edx,), %%cl   \n\t" // load Raw(x-bpp) into cl
  4451.  
  4452.    "paeth_paeth2:                  \n\t"
  4453.       "incl %%ebx                  \n\t"
  4454.       "incl %%edx                  \n\t"
  4455.       // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
  4456.       "addb %%cl, -1(%%edi,%%ebx,) \n\t"
  4457.       "cmpl _FullLength, %%ebx     \n\t"
  4458.       "jb paeth_lp2                \n\t"
  4459.  
  4460.    "paeth_end:                     \n\t"
  4461.       "EMMS                        \n\t" // end MMX; prep for poss. FP instrs.
  4462. #ifdef __PIC__
  4463.       "popl %%ebx                  \n\t" // restore index to Global Offset Table
  4464. #endif
  4465.  
  4466.       : "=c" (dummy_value_c),            // output regs (dummy)
  4467.         "=S" (dummy_value_S),
  4468.         "=D" (dummy_value_D)
  4469.  
  4470.       : "0" (bpp),       // ecx          // input regs
  4471.         "1" (prev_row),  // esi
  4472.         "2" (row)        // edi
  4473.  
  4474.       : "%eax", "%edx"                   // clobber list (no input regs!)
  4475. #ifndef __PIC__
  4476.       , "%ebx"
  4477. #endif
  4478.    );
  4479.  
  4480. } /* end png_read_filter_row_mmx_paeth() */
  4481. #endif
  4482.  
  4483.  
  4484.  
  4485.  
  4486. #ifdef PNG_THREAD_UNSAFE_OK
  4487. //===========================================================================//
  4488. //                                                                           //
  4489. //           P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B           //
  4490. //                                                                           //
  4491. //===========================================================================//
  4492.  
  4493. // Optimized code for PNG Sub filter decoder
  4494.  
  4495. static void /* PRIVATE */
  4496. png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
  4497. {
  4498.    int bpp;
  4499.    int dummy_value_a;
  4500.    int dummy_value_D;
  4501.  
  4502.    bpp = (row_info->pixel_depth + 7) >> 3;   // calc number of bytes per pixel
  4503.    _FullLength = row_info->rowbytes - bpp;   // number of bytes to filter
  4504.  
  4505.    __asm__ __volatile__ (
  4506. //pre "movl row, %%edi             \n\t"
  4507.       "movl %%edi, %%esi           \n\t" // lp = row
  4508. //pre "movl bpp, %%eax             \n\t"
  4509.       "addl %%eax, %%edi           \n\t" // rp = row + bpp
  4510. //irr "xorl %%eax, %%eax           \n\t"
  4511.       // get # of bytes to alignment
  4512.       "movl %%edi, _dif            \n\t" // take start of row
  4513.       "addl $0xf, _dif             \n\t" // add 7 + 8 to incr past
  4514.                                          //  alignment boundary
  4515.       "xorl %%ecx, %%ecx           \n\t"
  4516.       "andl $0xfffffff8, _dif      \n\t" // mask to alignment boundary
  4517.       "subl %%edi, _dif            \n\t" // subtract from start ==> value
  4518.       "jz sub_go                   \n\t" //  ecx at alignment
  4519.  
  4520.    "sub_lp1:                       \n\t" // fix alignment
  4521.       "movb (%%esi,%%ecx,), %%al   \n\t"
  4522.       "addb %%al, (%%edi,%%ecx,)   \n\t"
  4523.       "incl %%ecx                  \n\t"
  4524.       "cmpl _dif, %%ecx            \n\t"
  4525.       "jb sub_lp1                  \n\t"
  4526.  
  4527.    "sub_go:                        \n\t"
  4528.       "movl _FullLength, %%eax     \n\t"
  4529.       "movl %%eax, %%edx           \n\t"
  4530.       "subl %%ecx, %%edx           \n\t" // subtract alignment fix
  4531.       "andl $0x00000007, %%edx     \n\t" // calc bytes over mult of 8
  4532.       "subl %%edx, %%eax           \n\t" // drop over bytes from length
  4533.       "movl %%eax, _MMXLength      \n\t"
  4534.  
  4535.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4536.         "=D" (dummy_value_D)    // 1
  4537.  
  4538.       : "0" (bpp),              // eax    // input regs
  4539.         "1" (row)               // edi
  4540.  
  4541.       : "%esi", "%ecx", "%edx"            // clobber list
  4542.  
  4543. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4544.       , "%mm0", "%mm1", "%mm2", "%mm3"
  4545.       , "%mm4", "%mm5", "%mm6", "%mm7"
  4546. #endif
  4547.    );
  4548.  
  4549.    // now do the math for the rest of the row
  4550.    switch (bpp)
  4551.    {
  4552.       case 3:
  4553.       {
  4554.          _ActiveMask.use  = 0x0000ffffff000000LL;
  4555.          _ShiftBpp.use = 24;       // == 3 * 8
  4556.          _ShiftRem.use  = 40;      // == 64 - 24
  4557.  
  4558.          __asm__ __volatile__ (
  4559. // preload  "movl row, %%edi              \n\t"
  4560.             "movq _ActiveMask, %%mm7       \n\t" // load _ActiveMask for 2nd
  4561.                                                 //  active byte group
  4562.             "movl %%edi, %%esi            \n\t" // lp = row
  4563. // preload  "movl bpp, %%eax              \n\t"
  4564.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4565.             "movq %%mm7, %%mm6            \n\t"
  4566.             "movl _dif, %%edx             \n\t"
  4567.             "psllq _ShiftBpp, %%mm6       \n\t" // move mask in mm6 to cover
  4568.                                                 //  3rd active byte group
  4569.             // prime the pump:  load the first Raw(x-bpp) data set
  4570.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4571.  
  4572.          "sub_3lp:                        \n\t" // shift data for adding first
  4573.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4574.                                                 //  shift clears inactive bytes)
  4575.             // add 1st active group
  4576.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4577.             "paddb %%mm1, %%mm0           \n\t"
  4578.  
  4579.             // add 2nd active group
  4580.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4581.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4582.             "pand %%mm7, %%mm1            \n\t" // mask to use 2nd active group
  4583.             "paddb %%mm1, %%mm0           \n\t"
  4584.  
  4585.             // add 3rd active group
  4586.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4587.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4588.             "pand %%mm6, %%mm1            \n\t" // mask to use 3rd active group
  4589.             "addl $8, %%edx               \n\t"
  4590.             "paddb %%mm1, %%mm0           \n\t"
  4591.  
  4592.             "cmpl _MMXLength, %%edx       \n\t"
  4593.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
  4594.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4595.             "jb sub_3lp                   \n\t"
  4596.  
  4597.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4598.               "=D" (dummy_value_D)    // 1
  4599.  
  4600.             : "0" (bpp),              // eax    // input regs
  4601.               "1" (row)               // edi
  4602.  
  4603.             : "%edx", "%esi"                    // clobber list
  4604. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4605.             , "%mm0", "%mm1", "%mm6", "%mm7"
  4606. #endif
  4607.          );
  4608.       }
  4609.       break;
  4610.  
  4611.       case 1:
  4612.       {
  4613.          __asm__ __volatile__ (
  4614.             "movl _dif, %%edx            \n\t"
  4615. // preload  "movl row, %%edi             \n\t"
  4616.             "cmpl _FullLength, %%edx     \n\t"
  4617.             "jnb sub_1end                \n\t"
  4618.             "movl %%edi, %%esi           \n\t" // lp = row
  4619.             "xorl %%eax, %%eax           \n\t"
  4620. // preload  "movl bpp, %%eax             \n\t"
  4621.             "addl %%eax, %%edi           \n\t" // rp = row + bpp
  4622.  
  4623.          "sub_1lp:                       \n\t"
  4624.             "movb (%%esi,%%edx,), %%al   \n\t"
  4625.             "addb %%al, (%%edi,%%edx,)   \n\t"
  4626.             "incl %%edx                  \n\t"
  4627.             "cmpl _FullLength, %%edx     \n\t"
  4628.             "jb sub_1lp                  \n\t"
  4629.  
  4630.          "sub_1end:                      \n\t"
  4631.  
  4632.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4633.               "=D" (dummy_value_D)    // 1
  4634.  
  4635.             : "0" (bpp),              // eax    // input regs
  4636.               "1" (row)               // edi
  4637.  
  4638.             : "%edx", "%esi"                    // clobber list
  4639.          );
  4640.       }
  4641.       return;
  4642.  
  4643.       case 6:
  4644.       case 4:
  4645.       //case 7:   // GRR BOGUS
  4646.       //case 5:   // GRR BOGUS
  4647.       {
  4648.          _ShiftBpp.use = bpp << 3;
  4649.          _ShiftRem.use = 64 - _ShiftBpp.use;
  4650.  
  4651.          __asm__ __volatile__ (
  4652. // preload  "movl row, %%edi              \n\t"
  4653.             "movl _dif, %%edx             \n\t"
  4654.             "movl %%edi, %%esi            \n\t" // lp = row
  4655. // preload  "movl bpp, %%eax              \n\t"
  4656.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4657.  
  4658.             // prime the pump:  load the first Raw(x-bpp) data set
  4659.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4660.  
  4661.          "sub_4lp:                        \n\t" // shift data for adding first
  4662.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4663.                                                 //  shift clears inactive bytes)
  4664.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4665.             "paddb %%mm1, %%mm0           \n\t"
  4666.  
  4667.             // add 2nd active group
  4668.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4669.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4670.             "addl $8, %%edx               \n\t"
  4671.             "paddb %%mm1, %%mm0           \n\t"
  4672.  
  4673.             "cmpl _MMXLength, %%edx       \n\t"
  4674.             "movq %%mm0, -8(%%edi,%%edx,) \n\t"
  4675.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4676.             "jb sub_4lp                   \n\t"
  4677.  
  4678.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4679.               "=D" (dummy_value_D)    // 1
  4680.  
  4681.             : "0" (bpp),              // eax    // input regs
  4682.               "1" (row)               // edi
  4683.  
  4684.             : "%edx", "%esi"                    // clobber list
  4685. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4686.             , "%mm0", "%mm1"
  4687. #endif
  4688.          );
  4689.       }
  4690.       break;
  4691.  
  4692.       case 2:
  4693.       {
  4694.          _ActiveMask.use = 0x00000000ffff0000LL;
  4695.          _ShiftBpp.use = 16;       // == 2 * 8
  4696.          _ShiftRem.use = 48;       // == 64 - 16
  4697.  
  4698.          __asm__ __volatile__ (
  4699.             "movq _ActiveMask, %%mm7      \n\t" // load _ActiveMask for 2nd
  4700.                                                 //  active byte group
  4701.             "movl _dif, %%edx             \n\t"
  4702.             "movq %%mm7, %%mm6            \n\t"
  4703. // preload  "movl row, %%edi              \n\t"
  4704.             "psllq _ShiftBpp, %%mm6       \n\t" // move mask in mm6 to cover
  4705.                                                 //  3rd active byte group
  4706.             "movl %%edi, %%esi            \n\t" // lp = row
  4707.             "movq %%mm6, %%mm5            \n\t"
  4708. // preload  "movl bpp, %%eax              \n\t"
  4709.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4710.             "psllq _ShiftBpp, %%mm5       \n\t" // move mask in mm5 to cover
  4711.                                                 //  4th active byte group
  4712.             // prime the pump:  load the first Raw(x-bpp) data set
  4713.             "movq -8(%%edi,%%edx,), %%mm1 \n\t"
  4714.  
  4715.          "sub_2lp:                        \n\t" // shift data for adding first
  4716.             "psrlq _ShiftRem, %%mm1       \n\t" //  bpp bytes (no need for mask;
  4717.                                                 //  shift clears inactive bytes)
  4718.             // add 1st active group
  4719.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4720.             "paddb %%mm1, %%mm0           \n\t"
  4721.  
  4722.             // add 2nd active group
  4723.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4724.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4725.             "pand %%mm7, %%mm1            \n\t" // mask to use 2nd active group
  4726.             "paddb %%mm1, %%mm0           \n\t"
  4727.  
  4728.             // add 3rd active group
  4729.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4730.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4731.             "pand %%mm6, %%mm1            \n\t" // mask to use 3rd active group
  4732.             "paddb %%mm1, %%mm0           \n\t"
  4733.  
  4734.             // add 4th active group
  4735.             "movq %%mm0, %%mm1            \n\t" // mov updated Raws to mm1
  4736.             "psllq _ShiftBpp, %%mm1       \n\t" // shift data to pos. correctly
  4737.             "pand %%mm5, %%mm1            \n\t" // mask to use 4th active group
  4738.             "addl $8, %%edx               \n\t"
  4739.             "paddb %%mm1, %%mm0           \n\t"
  4740.             "cmpl _MMXLength, %%edx       \n\t"
  4741.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // write updated Raws to array
  4742.             "movq %%mm0, %%mm1            \n\t" // prep 1st add at top of loop
  4743.             "jb sub_2lp                   \n\t"
  4744.  
  4745.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4746.               "=D" (dummy_value_D)    // 1
  4747.  
  4748.             : "0" (bpp),              // eax    // input regs
  4749.               "1" (row)               // edi
  4750.  
  4751.             : "%edx", "%esi"                    // clobber list
  4752. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4753.             , "%mm0", "%mm1", "%mm5", "%mm6", "%mm7"
  4754. #endif
  4755.          );
  4756.       }
  4757.       break;
  4758.  
  4759.       case 8:
  4760.       {
  4761.          __asm__ __volatile__ (
  4762. // preload  "movl row, %%edi              \n\t"
  4763.             "movl _dif, %%edx             \n\t"
  4764.             "movl %%edi, %%esi            \n\t" // lp = row
  4765. // preload  "movl bpp, %%eax              \n\t"
  4766.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4767.             "movl _MMXLength, %%ecx       \n\t"
  4768.  
  4769.             // prime the pump:  load the first Raw(x-bpp) data set
  4770.             "movq -8(%%edi,%%edx,), %%mm7 \n\t"
  4771.             "andl $0x0000003f, %%ecx      \n\t" // calc bytes over mult of 64
  4772.  
  4773.          "sub_8lp:                        \n\t"
  4774.             "movq (%%edi,%%edx,), %%mm0   \n\t" // load Sub(x) for 1st 8 bytes
  4775.             "paddb %%mm7, %%mm0           \n\t"
  4776.             "movq 8(%%edi,%%edx,), %%mm1  \n\t" // load Sub(x) for 2nd 8 bytes
  4777.             "movq %%mm0, (%%edi,%%edx,)   \n\t" // write Raw(x) for 1st 8 bytes
  4778.  
  4779.             // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes.
  4780.             // This will be repeated for each group of 8 bytes with the 8th
  4781.             // group being used as the Raw(x-bpp) for the 1st group of the
  4782.             // next loop.
  4783.  
  4784.             "paddb %%mm0, %%mm1           \n\t"
  4785.             "movq 16(%%edi,%%edx,), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes
  4786.             "movq %%mm1, 8(%%edi,%%edx,)  \n\t" // write Raw(x) for 2nd 8 bytes
  4787.             "paddb %%mm1, %%mm2           \n\t"
  4788.             "movq 24(%%edi,%%edx,), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes
  4789.             "movq %%mm2, 16(%%edi,%%edx,) \n\t" // write Raw(x) for 3rd 8 bytes
  4790.             "paddb %%mm2, %%mm3           \n\t"
  4791.             "movq 32(%%edi,%%edx,), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes
  4792.             "movq %%mm3, 24(%%edi,%%edx,) \n\t" // write Raw(x) for 4th 8 bytes
  4793.             "paddb %%mm3, %%mm4           \n\t"
  4794.             "movq 40(%%edi,%%edx,), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes
  4795.             "movq %%mm4, 32(%%edi,%%edx,) \n\t" // write Raw(x) for 5th 8 bytes
  4796.             "paddb %%mm4, %%mm5           \n\t"
  4797.             "movq 48(%%edi,%%edx,), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes
  4798.             "movq %%mm5, 40(%%edi,%%edx,) \n\t" // write Raw(x) for 6th 8 bytes
  4799.             "paddb %%mm5, %%mm6           \n\t"
  4800.             "movq 56(%%edi,%%edx,), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes
  4801.             "movq %%mm6, 48(%%edi,%%edx,) \n\t" // write Raw(x) for 7th 8 bytes
  4802.             "addl $64, %%edx              \n\t"
  4803.             "paddb %%mm6, %%mm7           \n\t"
  4804.             "cmpl %%ecx, %%edx            \n\t"
  4805.             "movq %%mm7, -8(%%edi,%%edx,) \n\t" // write Raw(x) for 8th 8 bytes
  4806.             "jb sub_8lp                   \n\t"
  4807.  
  4808.             "cmpl _MMXLength, %%edx       \n\t"
  4809.             "jnb sub_8lt8                 \n\t"
  4810.  
  4811.          "sub_8lpA:                       \n\t"
  4812.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4813.             "addl $8, %%edx               \n\t"
  4814.             "paddb %%mm7, %%mm0           \n\t"
  4815.             "cmpl _MMXLength, %%edx       \n\t"
  4816.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // -8 to offset early addl edx
  4817.             "movq %%mm0, %%mm7            \n\t" // move calculated Raw(x) data
  4818.                                                 //  to mm1 to be new Raw(x-bpp)
  4819.                                                 //  for next loop
  4820.             "jb sub_8lpA                  \n\t"
  4821.  
  4822.          "sub_8lt8:                       \n\t"
  4823.  
  4824.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4825.               "=D" (dummy_value_D)    // 1
  4826.  
  4827.             : "0" (bpp),              // eax    // input regs
  4828.               "1" (row)               // edi
  4829.  
  4830.             : "%ecx", "%edx", "%esi"            // clobber list
  4831. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4832.             , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7"
  4833. #endif
  4834.          );
  4835.       }
  4836.       break;
  4837.  
  4838.       default:                // bpp greater than 8 bytes   GRR BOGUS
  4839.       {
  4840.          __asm__ __volatile__ (
  4841.             "movl _dif, %%edx             \n\t"
  4842. // preload  "movl row, %%edi              \n\t"
  4843.             "movl %%edi, %%esi            \n\t" // lp = row
  4844. // preload  "movl bpp, %%eax              \n\t"
  4845.             "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4846.  
  4847.          "sub_Alp:                        \n\t"
  4848.             "movq (%%edi,%%edx,), %%mm0   \n\t"
  4849.             "movq (%%esi,%%edx,), %%mm1   \n\t"
  4850.             "addl $8, %%edx               \n\t"
  4851.             "paddb %%mm1, %%mm0           \n\t"
  4852.             "cmpl _MMXLength, %%edx       \n\t"
  4853.             "movq %%mm0, -8(%%edi,%%edx,) \n\t" // mov does not affect flags;
  4854.                                                 //  -8 to offset addl edx
  4855.             "jb sub_Alp                   \n\t"
  4856.  
  4857.             : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4858.               "=D" (dummy_value_D)    // 1
  4859.  
  4860.             : "0" (bpp),              // eax    // input regs
  4861.               "1" (row)               // edi
  4862.  
  4863.             : "%edx", "%esi"                    // clobber list
  4864. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  4865.             , "%mm0", "%mm1"
  4866. #endif
  4867.          );
  4868.       }
  4869.       break;
  4870.  
  4871.    } // end switch (bpp)
  4872.  
  4873.    __asm__ __volatile__ (
  4874.       "movl _MMXLength, %%edx       \n\t"
  4875. //pre "movl row, %%edi              \n\t"
  4876.       "cmpl _FullLength, %%edx      \n\t"
  4877.       "jnb sub_end                  \n\t"
  4878.  
  4879.       "movl %%edi, %%esi            \n\t" // lp = row
  4880. //pre "movl bpp, %%eax              \n\t"
  4881.       "addl %%eax, %%edi            \n\t" // rp = row + bpp
  4882.       "xorl %%eax, %%eax            \n\t"
  4883.  
  4884.    "sub_lp2:                        \n\t"
  4885.       "movb (%%esi,%%edx,), %%al    \n\t"
  4886.       "addb %%al, (%%edi,%%edx,)    \n\t"
  4887.       "incl %%edx                   \n\t"
  4888.       "cmpl _FullLength, %%edx      \n\t"
  4889.       "jb sub_lp2                   \n\t"
  4890.  
  4891.    "sub_end:                        \n\t"
  4892.       "EMMS                         \n\t" // end MMX instructions
  4893.  
  4894.       : "=a" (dummy_value_a),   // 0      // output regs (dummy)
  4895.         "=D" (dummy_value_D)    // 1
  4896.  
  4897.       : "0" (bpp),              // eax    // input regs
  4898.         "1" (row)               // edi
  4899.  
  4900.       : "%edx", "%esi"                    // clobber list
  4901.    );
  4902.  
  4903. } // end of png_read_filter_row_mmx_sub()
  4904. #endif
  4905.  
  4906.  
  4907.  
  4908.  
  4909. //===========================================================================//
  4910. //                                                                           //
  4911. //            P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P            //
  4912. //                                                                           //
  4913. //===========================================================================//
  4914.  
  4915. // Optimized code for PNG Up filter decoder
  4916.  
  4917. static void /* PRIVATE */
  4918. png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
  4919.                            png_bytep prev_row)
  4920. {
  4921.    png_uint_32 len;
  4922.    int dummy_value_d;   // fix 'forbidden register 3 (dx) was spilled' error
  4923.    int dummy_value_S;
  4924.    int dummy_value_D;
  4925.  
  4926.    len = row_info->rowbytes;              // number of bytes to filter
  4927.  
  4928.    __asm__ __volatile__ (
  4929. //pre "movl row, %%edi              \n\t"
  4930.       // get # of bytes to alignment
  4931. #ifdef __PIC__
  4932.       "pushl %%ebx                  \n\t"
  4933. #endif
  4934.       "movl %%edi, %%ecx            \n\t"
  4935.       "xorl %%ebx, %%ebx            \n\t"
  4936.       "addl $0x7, %%ecx             \n\t"
  4937.       "xorl %%eax, %%eax            \n\t"
  4938.       "andl $0xfffffff8, %%ecx      \n\t"
  4939. //pre "movl prev_row, %%esi         \n\t"
  4940.       "subl %%edi, %%ecx            \n\t"
  4941.       "jz up_go                     \n\t"
  4942.  
  4943.    "up_lp1:                         \n\t" // fix alignment
  4944.       "movb (%%edi,%%ebx,), %%al    \n\t"
  4945.       "addb (%%esi,%%ebx,), %%al    \n\t"
  4946.       "incl %%ebx                   \n\t"
  4947.       "cmpl %%ecx, %%ebx            \n\t"
  4948.       "movb %%al, -1(%%edi,%%ebx,)  \n\t" // mov does not affect flags; -1 to
  4949.       "jb up_lp1                    \n\t" //  offset incl ebx
  4950.  
  4951.    "up_go:                          \n\t"
  4952. //pre "movl len, %%edx              \n\t"
  4953.       "movl %%edx, %%ecx            \n\t"
  4954.       "subl %%ebx, %%edx            \n\t" // subtract alignment fix
  4955.       "andl $0x0000003f, %%edx      \n\t" // calc bytes over mult of 64
  4956.       "subl %%edx, %%ecx            \n\t" // drop over bytes from length
  4957.  
  4958.       // unrolled loop - use all MMX registers and interleave to reduce
  4959.       // number of branch instructions (loops) and reduce partial stalls
  4960.    "up_loop:                        \n\t"
  4961.       "movq (%%esi,%%ebx,), %%mm1   \n\t"
  4962.       "movq (%%edi,%%ebx,), %%mm0   \n\t"
  4963.       "movq 8(%%esi,%%ebx,), %%mm3  \n\t"
  4964.       "paddb %%mm1, %%mm0           \n\t"
  4965.       "movq 8(%%edi,%%ebx,), %%mm2  \n\t"
  4966.       "movq %%mm0, (%%edi,%%ebx,)   \n\t"
  4967.       "paddb %%mm3, %%mm2           \n\t"
  4968.       "movq 16(%%esi,%%ebx,), %%mm5 \n\t"
  4969.       "movq %%mm2, 8(%%edi,%%ebx,)  \n\t"
  4970.       "movq 16(%%edi,%%ebx,), %%mm4 \n\t"
  4971.       "movq 24(%%esi,%%ebx,), %%mm7 \n\t"
  4972.       "paddb %%mm5, %%mm4           \n\t"
  4973.       "movq 24(%%edi,%%ebx,), %%mm6 \n\t"
  4974.       "movq %%mm4, 16(%%edi,%%ebx,) \n\t"
  4975.       "paddb %%mm7, %%mm6           \n\t"
  4976.       "movq 32(%%esi,%%ebx,), %%mm1 \n\t"
  4977.       "movq %%mm6, 24(%%edi,%%ebx,) \n\t"
  4978.       "movq 32(%%edi,%%ebx,), %%mm0 \n\t"
  4979.       "movq 40(%%esi,%%ebx,), %%mm3 \n\t"
  4980.       "paddb %%mm1, %%mm0           \n\t"
  4981.       "movq 40(%%edi,%%ebx,), %%mm2 \n\t"
  4982.       "movq %%mm0, 32(%%edi,%%ebx,) \n\t"
  4983.       "paddb %%mm3, %%mm2           \n\t"
  4984.       "movq 48(%%esi,%%ebx,), %%mm5 \n\t"
  4985.       "movq %%mm2, 40(%%edi,%%ebx,) \n\t"
  4986.       "movq 48(%%edi,%%ebx,), %%mm4 \n\t"
  4987.       "movq 56(%%esi,%%ebx,), %%mm7 \n\t"
  4988.       "paddb %%mm5, %%mm4           \n\t"
  4989.       "movq 56(%%edi,%%ebx,), %%mm6 \n\t"
  4990.       "movq %%mm4, 48(%%edi,%%ebx,) \n\t"
  4991.       "addl $64, %%ebx              \n\t"
  4992.       "paddb %%mm7, %%mm6           \n\t"
  4993.       "cmpl %%ecx, %%ebx            \n\t"
  4994.       "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags;
  4995.       "jb up_loop                   \n\t" //  -8 to offset addl ebx
  4996.  
  4997.       "cmpl $0, %%edx               \n\t" // test for bytes over mult of 64
  4998.       "jz up_end                    \n\t"
  4999.  
  5000.       "cmpl $8, %%edx               \n\t" // test for less than 8 bytes
  5001.       "jb up_lt8                    \n\t" //  [added by lcreeve at netins.net]
  5002.  
  5003.       "addl %%edx, %%ecx            \n\t"
  5004.       "andl $0x00000007, %%edx      \n\t" // calc bytes over mult of 8
  5005.       "subl %%edx, %%ecx            \n\t" // drop over bytes from length
  5006.       "jz up_lt8                    \n\t"
  5007.  
  5008.    "up_lpA:                         \n\t" // use MMX regs to update 8 bytes sim.
  5009.       "movq (%%esi,%%ebx,), %%mm1   \n\t"
  5010.       "movq (%%edi,%%ebx,), %%mm0   \n\t"
  5011.       "addl $8, %%ebx               \n\t"
  5012.       "paddb %%mm1, %%mm0           \n\t"
  5013.       "cmpl %%ecx, %%ebx            \n\t"
  5014.       "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to
  5015.       "jb up_lpA                    \n\t" //  offset add ebx
  5016.       "cmpl $0, %%edx               \n\t" // test for bytes over mult of 8
  5017.       "jz up_end                    \n\t"
  5018.  
  5019.    "up_lt8:                         \n\t"
  5020.       "xorl %%eax, %%eax            \n\t"
  5021.       "addl %%edx, %%ecx            \n\t" // move over byte count into counter
  5022.  
  5023.    "up_lp2:                         \n\t" // use x86 regs for remaining bytes
  5024.       "movb (%%edi,%%ebx,), %%al    \n\t"
  5025.       "addb (%%esi,%%ebx,), %%al    \n\t"
  5026.       "incl %%ebx                   \n\t"
  5027.       "cmpl %%ecx, %%ebx            \n\t"
  5028.       "movb %%al, -1(%%edi,%%ebx,)  \n\t" // mov does not affect flags; -1 to
  5029.       "jb up_lp2                    \n\t" //  offset inc ebx
  5030.  
  5031.    "up_end:                         \n\t"
  5032.       "EMMS                         \n\t" // conversion of filtered row complete
  5033. #ifdef __PIC__
  5034.       "popl %%ebx                   \n\t"
  5035. #endif
  5036.  
  5037.       : "=d" (dummy_value_d),   // 0      // output regs (dummy)
  5038.         "=S" (dummy_value_S),   // 1
  5039.         "=D" (dummy_value_D)    // 2
  5040.  
  5041.       : "0" (len),              // edx    // input regs
  5042.         "1" (prev_row),         // esi
  5043.         "2" (row)               // edi
  5044.  
  5045.       : "%eax", "%ecx"            // clobber list (no input regs!)
  5046. #ifndef __PIC__
  5047.       , "%ebx"
  5048. #endif
  5049.  
  5050. #if 0  /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */
  5051.       , "%mm0", "%mm1", "%mm2", "%mm3"
  5052.       , "%mm4", "%mm5", "%mm6", "%mm7"
  5053. #endif
  5054.    );
  5055.  
  5056. } // end of png_read_filter_row_mmx_up()
  5057.  
  5058. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5059.  
  5060.  
  5061.  
  5062.  
  5063. /*===========================================================================*/
  5064. /*                                                                           */
  5065. /*                   P N G _ R E A D _ F I L T E R _ R O W                   */
  5066. /*                                                                           */
  5067. /*===========================================================================*/
  5068.  
  5069.  
  5070. /* Optimized png_read_filter_row routines */
  5071.  
  5072. void /* PRIVATE */
  5073. png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
  5074.    row, png_bytep prev_row, int filter)
  5075. {
  5076. #ifdef PNG_DEBUG
  5077.    char filnm[10];
  5078. #endif
  5079.  
  5080. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  5081. /* GRR:  these are superseded by png_ptr->asm_flags: */
  5082. #define UseMMX_sub    1   // GRR:  converted 20000730
  5083. #define UseMMX_up     1   // GRR:  converted 20000729
  5084. #define UseMMX_avg    1   // GRR:  converted 20000828 (+ 16-bit bugfix 20000916)
  5085. #define UseMMX_paeth  1   // GRR:  converted 20000828
  5086.  
  5087.    if (_mmx_supported == 2) {
  5088.        /* this should have happened in png_init_mmx_flags() already */
  5089. #if !defined(PNG_1_0_X)
  5090.        png_warning(png_ptr, "asm_flags may not have been initialized");
  5091. #endif
  5092.        png_mmx_support();
  5093.    }
  5094. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5095.  
  5096. #ifdef PNG_DEBUG
  5097.    png_debug(1, "in png_read_filter_row (pnggccrd.c)\n");
  5098.    switch (filter)
  5099.    {
  5100.       case 0: sprintf(filnm, "none");
  5101.          break;
  5102.       case 1: sprintf(filnm, "sub-%s",
  5103. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5104. #if !defined(PNG_1_0_X)
  5105.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : 
  5106. #endif
  5107. #endif
  5108. "x86");
  5109.          break;
  5110.       case 2: sprintf(filnm, "up-%s",
  5111. #ifdef PNG_ASSEMBLER_CODE_SUPPORTED
  5112. #if !defined(PNG_1_0_X)
  5113.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" :
  5114. #endif
  5115. #endif
  5116.  "x86");
  5117.          break;
  5118.       case 3: sprintf(filnm, "avg-%s",
  5119. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5120. #if !defined(PNG_1_0_X)
  5121.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" :
  5122. #endif
  5123. #endif
  5124.  "x86");
  5125.          break;
  5126.       case 4: sprintf(filnm, "Paeth-%s",
  5127. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5128. #if !defined(PNG_1_0_X)
  5129.         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":
  5130. #endif
  5131. #endif
  5132. "x86");
  5133.          break;
  5134.       default: sprintf(filnm, "unknw");
  5135.          break;
  5136.    }
  5137.    png_debug2(0, "row_number=%5ld, %5s, ", png_ptr->row_number, filnm);
  5138.    png_debug1(0, "row=0x%08lx, ", (unsigned long)row);
  5139.    png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth,
  5140.       (int)((row_info->pixel_depth + 7) >> 3));
  5141.    png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes);
  5142. #endif /* PNG_DEBUG */
  5143.  
  5144.    switch (filter)
  5145.    {
  5146.       case PNG_FILTER_VALUE_NONE:
  5147.          break;
  5148.  
  5149.       case PNG_FILTER_VALUE_SUB:
  5150. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5151. #if !defined(PNG_1_0_X)
  5152.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
  5153.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  5154.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  5155. #else
  5156.          if (_mmx_supported)
  5157. #endif
  5158.          {
  5159.             png_read_filter_row_mmx_sub(row_info, row);
  5160.          }
  5161.          else
  5162. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5163.          {
  5164.             png_uint_32 i;
  5165.             png_uint_32 istop = row_info->rowbytes;
  5166.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  5167.             png_bytep rp = row + bpp;
  5168.             png_bytep lp = row;
  5169.  
  5170.             for (i = bpp; i < istop; i++)
  5171.             {
  5172.                *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
  5173.                rp++;
  5174.             }
  5175.          }  /* end !UseMMX_sub */
  5176.          break;
  5177.  
  5178.       case PNG_FILTER_VALUE_UP:
  5179. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
  5180. #if !defined(PNG_1_0_X)
  5181.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
  5182.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  5183.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  5184. #else
  5185.          if (_mmx_supported)
  5186. #endif
  5187.          {
  5188.             png_read_filter_row_mmx_up(row_info, row, prev_row);
  5189.          }
  5190.           else
  5191. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5192.          {
  5193.             png_uint_32 i;
  5194.             png_uint_32 istop = row_info->rowbytes;
  5195.             png_bytep rp = row;
  5196.             png_bytep pp = prev_row;
  5197.  
  5198.             for (i = 0; i < istop; ++i)
  5199.             {
  5200.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  5201.                rp++;
  5202.             }
  5203.          }  /* end !UseMMX_up */
  5204.          break;
  5205.  
  5206.       case PNG_FILTER_VALUE_AVG:
  5207. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5208. #if !defined(PNG_1_0_X)
  5209.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
  5210.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  5211.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  5212. #else
  5213.          if (_mmx_supported)
  5214. #endif
  5215.          {
  5216.             png_read_filter_row_mmx_avg(row_info, row, prev_row);
  5217.          }
  5218.          else
  5219. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5220.          {
  5221.             png_uint_32 i;
  5222.             png_bytep rp = row;
  5223.             png_bytep pp = prev_row;
  5224.             png_bytep lp = row;
  5225.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  5226.             png_uint_32 istop = row_info->rowbytes - bpp;
  5227.  
  5228.             for (i = 0; i < bpp; i++)
  5229.             {
  5230.                *rp = (png_byte)(((int)(*rp) +
  5231.                   ((int)(*pp++) >> 1)) & 0xff);
  5232.                rp++;
  5233.             }
  5234.  
  5235.             for (i = 0; i < istop; i++)
  5236.             {
  5237.                *rp = (png_byte)(((int)(*rp) +
  5238.                   ((int)(*pp++ + *lp++) >> 1)) & 0xff);
  5239.                rp++;
  5240.             }
  5241.          }  /* end !UseMMX_avg */
  5242.          break;
  5243.  
  5244.       case PNG_FILTER_VALUE_PAETH:
  5245. #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_THREAD_UNSAFE_OK)
  5246. #if !defined(PNG_1_0_X)
  5247.          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
  5248.              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
  5249.              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
  5250. #else
  5251.          if (_mmx_supported)
  5252. #endif
  5253.          {
  5254.             png_read_filter_row_mmx_paeth(row_info, row, prev_row);
  5255.          }
  5256.          else
  5257. #endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
  5258.          {
  5259.             png_uint_32 i;
  5260.             png_bytep rp = row;
  5261.             png_bytep pp = prev_row;
  5262.             png_bytep lp = row;
  5263.             png_bytep cp = prev_row;
  5264.             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
  5265.             png_uint_32 istop = row_info->rowbytes - bpp;
  5266.  
  5267.             for (i = 0; i < bpp; i++)
  5268.             {
  5269.                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
  5270.                rp++;
  5271.             }
  5272.  
  5273.             for (i = 0; i < istop; i++)   /* use leftover rp,pp */
  5274.             {
  5275.                int a, b, c, pa, pb, pc, p;
  5276.  
  5277.                a = *lp++;
  5278.                b = *pp++;
  5279.                c = *cp++;
  5280.  
  5281.                p = b - c;
  5282.                pc = a - c;
  5283.  
  5284. #ifdef PNG_USE_ABS
  5285.                pa = abs(p);
  5286.                pb = abs(pc);
  5287.                pc = abs(p + pc);
  5288. #else
  5289.                pa = p < 0 ? -p : p;
  5290.                pb = pc < 0 ? -pc : pc;
  5291.                pc = (p + pc) < 0 ? -(p + pc) : p + pc;
  5292. #endif
  5293.  
  5294.                /*
  5295.                   if (pa <= pb && pa <= pc)
  5296.                      p = a;
  5297.                   else if (pb <= pc)
  5298.                      p = b;
  5299.                   else
  5300.                      p = c;
  5301.                 */
  5302.  
  5303.                p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
  5304.  
  5305.                *rp = (png_byte)(((int)(*rp) + p) & 0xff);
  5306.                rp++;
  5307.             }
  5308.          }  /* end !UseMMX_paeth */
  5309.          break;
  5310.  
  5311.       default:
  5312.          png_warning(png_ptr, "Ignoring bad row-filter type");
  5313.          *row=0;
  5314.          break;
  5315.    }
  5316. }
  5317.  
  5318. #endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
  5319.  
  5320.  
  5321. /*===========================================================================*/
  5322. /*                                                                           */
  5323. /*                      P N G _ M M X _ S U P P O R T                        */
  5324. /*                                                                           */
  5325. /*===========================================================================*/
  5326.  
  5327. /* GRR NOTES:  (1) the following code assumes 386 or better (pushfl/popfl)
  5328.  *             (2) all instructions compile with gcc 2.7.2.3 and later
  5329.  *             (3) the function is moved down here to prevent gcc from
  5330.  *                  inlining it in multiple places and then barfing be-
  5331.  *                  cause the ".NOT_SUPPORTED" label is multiply defined
  5332.  *             [is there a way to signal that a *single* function should
  5333.  *              not be inlined?  is there a way to modify the label for
  5334.  *              each inlined instance, e.g., by appending _1, _2, etc.?
  5335.  *              maybe if don't use leading "." in label name? (nope...sigh)]
  5336.  */
  5337.  
  5338. int PNGAPI
  5339. png_mmx_support(void)
  5340. {
  5341. #if defined(PNG_MMX_CODE_SUPPORTED)
  5342.     __asm__ __volatile__ (
  5343.         "pushl %%ebx          \n\t"  // ebx gets clobbered by CPUID instruction
  5344.         "pushl %%ecx          \n\t"  // so does ecx...
  5345.         "pushl %%edx          \n\t"  // ...and edx (but ecx & edx safe on Linux)
  5346. //      ".byte  0x66          \n\t"  // convert 16-bit pushf to 32-bit pushfd
  5347. //      "pushf                \n\t"  // 16-bit pushf
  5348.         "pushfl               \n\t"  // save Eflag to stack
  5349.         "popl %%eax           \n\t"  // get Eflag from stack into eax
  5350.         "movl %%eax, %%ecx    \n\t"  // make another copy of Eflag in ecx
  5351.         "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21)
  5352.         "pushl %%eax          \n\t"  // save modified Eflag back to stack
  5353. //      ".byte  0x66          \n\t"  // convert 16-bit popf to 32-bit popfd
  5354. //      "popf                 \n\t"  // 16-bit popf
  5355.         "popfl                \n\t"  // restore modified value to Eflag reg
  5356.         "pushfl               \n\t"  // save Eflag to stack
  5357.         "popl %%eax           \n\t"  // get Eflag from stack
  5358.         "pushl %%ecx          \n\t"  // save original Eflag to stack
  5359.         "popfl                \n\t"  // restore original Eflag
  5360.         "xorl %%ecx, %%eax    \n\t"  // compare new Eflag with original Eflag
  5361.         "jz 0f                \n\t"  // if same, CPUID instr. is not supported
  5362.  
  5363.         "xorl %%eax, %%eax    \n\t"  // set eax to zero
  5364. //      ".byte  0x0f, 0xa2    \n\t"  // CPUID instruction (two-byte opcode)
  5365.         "cpuid                \n\t"  // get the CPU identification info
  5366.         "cmpl $1, %%eax       \n\t"  // make sure eax return non-zero value
  5367.         "jl 0f                \n\t"  // if eax is zero, MMX is not supported
  5368.  
  5369.         "xorl %%eax, %%eax    \n\t"  // set eax to zero and...
  5370.         "incl %%eax           \n\t"  // ...increment eax to 1.  This pair is
  5371.                                      // faster than the instruction "mov eax, 1"
  5372.         "cpuid                \n\t"  // get the CPU identification info again
  5373.         "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23)
  5374.         "cmpl $0, %%edx       \n\t"  // 0 = MMX not supported
  5375.         "jz 0f                \n\t"  // non-zero = yes, MMX IS supported
  5376.  
  5377.         "movl $1, %%eax       \n\t"  // set return value to 1
  5378.         "jmp  1f              \n\t"  // DONE:  have MMX support
  5379.  
  5380.     "0:                       \n\t"  // .NOT_SUPPORTED: target label for jump instructions
  5381.         "movl $0, %%eax       \n\t"  // set return value to 0
  5382.     "1:                       \n\t"  // .RETURN: target label for jump instructions
  5383.         "movl %%eax, _mmx_supported \n\t" // save in global static variable, too
  5384.         "popl %%edx           \n\t"  // restore edx
  5385.         "popl %%ecx           \n\t"  // restore ecx
  5386.         "popl %%ebx           \n\t"  // restore ebx
  5387.  
  5388. //      "ret                  \n\t"  // DONE:  no MMX support
  5389.                                      // (fall through to standard C "ret")
  5390.  
  5391.         :                            // output list (none)
  5392.  
  5393.         :                            // any variables used on input (none)
  5394.  
  5395.         : "%eax"                     // clobber list
  5396. //      , "%ebx", "%ecx", "%edx"     // GRR:  we handle these manually
  5397. //      , "memory"   // if write to a variable gcc thought was in a reg
  5398. //      , "cc"       // "condition codes" (flag bits)
  5399.     );
  5400. #else     
  5401.     _mmx_supported = 0;
  5402. #endif /* PNG_MMX_CODE_SUPPORTED */
  5403.  
  5404.     return _mmx_supported;
  5405. }
  5406.  
  5407.  
  5408. #endif /* PNG_USE_PNGGCCRD */
  5409.